tmf: document how to add a trace type
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.help / doc / User-Guide.mediawiki
CommitLineData
067490ab
AM
1
2= Introduction =
3
4The purpose of the '''Tracing Monitoring Framework (TMF)''' is to facilitate the integration of tracing and monitoring tools into Eclipse, to provide out-of-the-box generic functionalities/views and provide extension mechanisms of the base functionalities for application specific purposes.
5
6f182760
PT
6= Component Interaction =
7
8TMF provides a mechanism for different components to interact with each other using signals. The signals can carry information that is specific to each signal.
9
10The TMF Signal Manager handles registration of components and the broadcasting of signals to their intended receivers.
11
12Components can register as VIP receivers which will ensure they will receive the signal before non-VIP receivers.
13
14== Sending Signals ==
15
16In order to send a signal, an instance of the signal must be created and passed as argument to the signal manager to be dispatched. Every component that can handle the signal will receive it. The receivers do not need to be known by the sender.
17
18<pre>
19TmfExampleSignal signal = new TmfExampleSignal(this, ...);
20TmfSignalManager.dispatchSignal(signal);
21</pre>
22
23If the sender is an instance of the class TmfComponent, the broadcast method can be used:
24
25<pre>
26TmfExampleSignal signal = new TmfExampleSignal(this, ...);
27broadcast(signal);
28</pre>
29
30== Receiving Signals ==
31
32In order to receive any signal, the receiver must first be registered with the signal manager. The receiver can register as a normal or VIP receiver.
33
34<pre>
35TmfSignalManager.register(this);
36TmfSignalManager.registerVIP(this);
37</pre>
38
39If the receiver is an instance of the class TmfComponent, it is automatically registered as a normal receiver in the constructor.
40
41When the receiver is destroyed or disposed, it should deregister itself from the signal manager.
42
43<pre>
44TmfSignalManager.deregister(this);
45</pre>
46
47To actually receive and handle any specific signal, the receiver must use the @TmfSignalHandler annotation and implement a method that will be called when the signal is broadcast. The name of the method is irrelevant.
48
49<pre>
50@TmfSignalHandler
51public void example(TmfExampleSignal signal) {
52 ...
53}
54</pre>
55
56The source of the signal can be used, if necessary, by a component to filter out and ignore a signal that was broadcast by itself when the component is also a receiver of the signal but only needs to handle it when it was sent by another component or another instance of the component.
57
58== Signal Throttling ==
59
60It is possible for a TmfComponent instance to buffer the dispatching of signals so that only the last signal queued after a specified delay without any other signal queued is sent to the receivers. All signals that are preempted by a newer signal within the delay are discarded.
61
62The signal throttler must first be initialized:
63
64<pre>
65final int delay = 100; // in ms
66TmfSignalThrottler throttler = new TmfSignalThrottler(this, delay);
67</pre>
68
69Then the sending of signals should be queued through the throttler:
70
71<pre>
72TmfExampleSignal signal = new TmfExampleSignal(this, ...);
73throttler.queue(signal);
74</pre>
75
76When the throttler is no longer needed, it should be disposed:
77
78<pre>
79throttler.dispose();
80</pre>
81
82== Signal Reference ==
83
84The following is a list of built-in signals defined in the framework.
85
86=== TmfStartSynchSignal ===
87
88''Purpose''
89
90This signal is used to indicate the start of broadcasting of a signal. Internally, the data provider will not fire event requests until the corresponding TmfEndSynchSignal signal is received. This allows coalescing of requests triggered by multiple receivers of the broadcast signal.
91
92''Senders''
93
94Sent by TmfSignalManager before dispatching a signal to all receivers.
95
96''Receivers''
97
98Received by TmfDataProvider.
99
100=== TmfEndSynchSignal ===
101
102''Purpose''
103
104This signal is used to indicate the end of broadcasting of a signal. Internally, the data provider fire all pending event requests that were received and buffered since the corresponding TmfStartSynchSignal signal was received. This allows coalescing of requests triggered by multiple receivers of the broadcast signal.
105
106''Senders''
107
108Sent by TmfSignalManager after dispatching a signal to all receivers.
109
110''Receivers''
111
112Received by TmfDataProvider.
113
114=== TmfTraceOpenedSignal ===
115
116''Purpose''
117
118This signal is used to indicate that a trace has been opened in an editor.
119
120''Senders''
121
122Sent by a TmfEventsEditor instance when it is created.
123
124''Receivers''
125
126Received by TmfTrace, TmfExperiment, TmfTraceManager and every view that shows trace data. Components that show trace data should handle this signal.
127
128=== TmfTraceSelectedSignal ===
129
130''Purpose''
131
132This signal is used to indicate that a trace has become the currently selected trace.
133
134''Senders''
135
136Sent by a TmfEventsEditor instance when it receives focus. Components can send this signal to make a trace editor be brought to front.
137
138''Receivers''
139
140Received by TmfTraceManager and every view that shows trace data. Components that show trace data should handle this signal.
141
142=== TmfTraceClosedSignal ===
143
144''Purpose''
145
146This signal is used to indicate that a trace editor has been closed.
147
148''Senders''
149
150Sent by a TmfEventsEditor instance when it is disposed.
151
152''Receivers''
153
154Received by TmfTraceManager and every view that shows trace data. Components that show trace data should handle this signal.
155
156=== TmfTraceRangeUpdatedSignal ===
157
158''Purpose''
159
160This signal is used to indicate that the valid time range of a trace has been updated. This triggers indexing of the trace up to the end of the range. In the context of streaming, this end time is considered a safe time up to which all events are guaranteed to have been completely received. For non-streaming traces, the end time is set to infinity indicating that all events can be read immediately. Any processing of trace events that wants to take advantage of request coalescing should be triggered by this signal.
161
162''Senders''
163
164Sent by TmfExperiment and non-streaming TmfTrace. Streaming traces should send this signal in the TmfTrace subclass when a new safe time is determined by a specific implementation.
165
166''Receivers''
167
168Received by TmfTrace, TmfExperiment and components that process trace events. Components that need to process trace events should handle this signal.
169
170=== TmfTraceUpdatedSignal ===
171
172''Purpose''
173
174This signal is used to indicate that new events have been indexed for a trace.
175
176''Senders''
177
178Sent by TmfCheckpointIndexer when new events have been indexed and the number of events has changed.
179
180''Receivers''
181
182Received by components that need to be notified of a new trace event count.
183
184=== TmfTimeSynchSignal ===
185
186''Purpose''
187
188This signal is used to indicate that a new time has been selected.
189
190''Senders''
191
192Sent by any component that allows the user to select a time.
193
194''Receivers''
195
196Received by any component that needs to be notified of the currently selected time.
197
198=== TmfRangeSynchSignal ===
199
200''Purpose''
201
202This signal is used to indicate that a new time range window has been set.
203
204''Senders''
205
206Sent by any component that allows the user to set a time range window.
207
208''Receivers''
209
210Received by any component that needs to be notified of the current visible time range window.
211
212=== TmfEventFilterAppliedSignal ===
213
214''Purpose''
215
216This signal is used to indicate that a filter has been applied to a trace.
217
218''Senders''
219
220Sent by TmfEventsTable when a filter is applied.
221
222''Receivers''
223
224Received by any component that shows trace data and needs to be notified of applied filters.
225
226=== TmfEventSearchAppliedSignal ===
227
228''Purpose''
229
230This signal is used to indicate that a search has been applied to a trace.
231
232''Senders''
233
234Sent by TmfEventsTable when a search is applied.
235
236''Receivers''
237
238Received by any component that shows trace data and needs to be notified of applied searches.
239
240=== TmfTimestampFormatUpdateSignal ===
241
242''Purpose''
243
244This signal is used to indicate that the timestamp format preference has been updated.
245
246''Senders''
247
248Sent by TmfTimestampFormat when the default timestamp format preference is changed.
249
250''Receivers''
251
252Received by any component that needs to refresh its display for the new timestamp format.
253
254=== TmfStatsUpdatedSignal ===
255
256''Purpose''
257
258This signal is used to indicate that the statistics data model has been updated.
259
260''Senders''
261
262Sent by statistic providers when new statistics data has been processed.
263
264''Receivers''
265
266Received by statistics viewers and any component that needs to be notified of a statistics update.
267
268== Debugging ==
269
270TMF has built-in Eclipse tracing support for the debugging of signal interaction between components. To enable it, open the '''Run/Debug Configuration...''' dialog, select a configuration, click the '''Tracing''' tab, select the plug-in '''org.eclipse.linuxtools.tmf.core''', and check the '''signal''' item.
271
272All signals sent and received will be logged to the file TmfTrace.log located in the Eclipse home directory.
273
067490ab
AM
274= TMF UML2 Sequence Diagram Framework =
275
276The purpose of the UML2 Sequence Diagram Framework of TMF is to provide a framework for generation of UML2 sequence diagrams. It provides
277*UML2 Sequence diagram drawing capabilities (i.e. lifelines, messages, activations, object creation and deletion)
278*a generic, re-usable Sequence Diagram View
279*Eclipse Extension Point for the creation of sequence diagrams
280*callback hooks for searching and filtering within the Sequence Diagram View
281*scalability<br>
282The following chapters describe the Sequence Diagram Framework as well as a reference implementation and its usage.
283
284== TMF UML2 Sequence Diagram Extensions ==
285
286In the UML2 Sequence Diagram Framework an Eclipse extension point is defined so that other plug-ins can contribute code to create sequence diagram.
287
288'''Identifier''': org.eclipse.linuxtools.tmf.ui.uml2SDLoader<br>
289'''Since''': Since 0.3.2 (based on UML2SD of org.eclipse.tptp.common.ui)<br>
290'''Description''': This extension point aims to list and connect any UML2 Sequence Diagram loader.<br>
291'''Configuration Markup''':<br>
292
293<pre>
294<!ELEMENT extension (uml2SDLoader)+>
295<!ATTLIST extension
296point CDATA #REQUIRED
297id CDATA #IMPLIED
298name CDATA #IMPLIED
299>
300</pre>
301
302*point - A fully qualified identifier of the target extension point.
303*id - An optional identifier of the extension instance.
304*name - An optional name of the extension instance.
305
306<pre>
307<!ELEMENT uml2SDLoader EMPTY>
308<!ATTLIST uml2SDLoader
309id CDATA #REQUIRED
310name CDATA #REQUIRED
311class CDATA #REQUIRED
312view CDATA #REQUIRED
313default (true | false)
314</pre>
315
fac4e45b 316*id - A unique identifier for this uml2SDLoader. This is not mandatory as long as the id attribute cannot be retrieved by the provider plug-in. The class attribute is the one on which the underlying algorithm relies.
067490ab
AM
317*name - An name of the extension instance.
318*class - The implementation of this UML2 SD viewer loader. The class must implement org.eclipse.linuxtools.tmf.ui.views.uml2sd.load.IUml2SDLoader.
319*view - The view ID of the view that this loader aims to populate. Either org.eclipse.linuxtools.tmf.ui.views.uml2sd.SDView itself or a extension of org.eclipse.linuxtools.tmf.ui.views.uml2sd.SDView.
320*default - Set to true to make this loader the default one for the view; in case of several default loaders, first one coming from extensions list is taken.
321
322
323== Management of the Extension Point ==
324
325The TMF UI plug-in is responsible for evaluating each contribution to the extension point.
326<br>
327<br>
328With this extension point, a loader class is associated with a Sequence Diagram View. Multiple loaders can be associated to a single Sequence Diagram View. However, additional means have to be implemented to specify which loader should be used when opening the view. For example, an eclipse action or command could be used for that. This additional code is not necessary if there is only one loader for a given Sequence Diagram View associated and this loader has the attribute "default" set to "true". (see also [[#Using one Sequence Diagram View with Multiple Loaders | Using one Sequence Diagram View with Multiple Loaders]])
329
330== Sequence Diagram View ==
331
332For this extension point a Sequence Diagram View has to be defined as well. The Sequence Diagram View class implementation is provided by the plug-in ''org.eclipse.linuxtools.tmf.ui'' (''org.eclipse.linuxtools.tmf.ui.views.uml2sd.SDView'') and can be used as is or can also be sub-classed. For that, a view extension has to be added to the ''plugin.xml''.
333
334=== Supported Widgets ===
335
336The loader class provides a frame containing all the UML2 widgets to be displayed. The following widgets exist:
337
338*Lifeline
339*Activation
340*Synchronous Message
341*Asynchronous Message
342*Synchronous Message Return
343*Asynchronous Message Return
344*Stop
345
346For a lifeline, a category can be defined. The lifeline category defines icons, which are displayed in the lifeline header.
347
348=== Zooming ===
349
350The Sequence Diagram View allows the user to zoom in, zoom out and reset the zoom factor.
351
352=== Printing ===
353
354It is possible to print the whole sequence diagram as well as part of it.
355
356=== Key Bindings ===
357
358*SHIFT+ALT+ARROW-DOWN - to scroll down within sequence diagram one view page at a time
359*SHIFT+ALT+ARROW-UP - to scroll up within sequence diagram one view page at a time
360*SHIFT+ALT+ARROW-RIGHT - to scroll right within sequence diagram one view page at a time
361*SHIFT+ALT+ARROW-LEFT - to scroll left within sequence diagram one view page at a time
362*SHIFT+ALT+ARROW-HOME - to jump to the beginning of the selected message if not already visible in page
363*SHIFT+ALT+ARROW-END - to jump to the end of the selected message if not already visible in page
364*CTRL+F - to open find dialog if either the basic or extended find provider is defined (see [[#Using the Find Provider Interface | Using the Find Provider Interface]])
365*CTRL+P - to open print dialog
366
367=== Preferences ===
368
369The UML2 Sequence Diagram Framework provides preferences to customize the appearance of the Sequence Diagram View. The color of all widgets and text as well as the fonts of the text of all widget can be adjust. Amongst others the default lifeline width can be alternated. To change preferences select '''Windows->Preferences->Tracing->UML2 Sequence Diagrams'''. The following preference page will show:<br>
370[[Image:images/SeqDiagramPref.png]] <br>
371After changing the preferences select '''OK'''.
372
373=== Callback hooks ===
374
375The Sequence Diagram View provides several callback hooks so that extension can provide application specific functionality. The following interfaces can be provided:
376* Basic find provider or extended find Provider<br> For finding within the sequence diagram
377* Basic filter provider and extended Filter Provider<br> For filtering within the sequnce diagram.
378* Basic paging provider or advanced paging provider<br> For scalability reasons, used to limit number of displayed messages
379* Properies provider<br> To provide properties of selected elements
380* Collapse provider <br> To collapse areas of the sequence diagram
381
382== Tutorial ==
383
384This tutorial describes how to create a UML2 Sequence Diagram Loader extension and use this loader in the in Eclipse.
385
386=== Prerequisites ===
387
388The tutorial is based on Eclipse 3.7 (Eclipse Indigo) and TMF 0.3.2.
389
390=== Creating an Eclipse UI Plug-in ===
391
392To create a new project with name org.eclipse.linuxtools.tmf.sample.ui select '''File -> New -> Project -> Plug-in Development -> Plug-in Project'''. <br>
393[[Image:images/Screenshot-NewPlug-inProject1.png]]<br>
394
395[[Image:images/Screenshot-NewPlug-inProject2.png]]<br>
396
f5b8868d 397[[Image:images/Screenshot-NewPlug-inProject3.png]]<br>
067490ab
AM
398
399=== Creating a Sequence Diagram View ===
400
401To open the plug-in manifest, double-click on the MANIFEST.MF file. <br>
402[[Image:images/SelectManifest.png]]<br>
403
404Change to the Dependencies tab and select '''Add...''' of the ''Required Plug-ins'' section. A new dialog box will open. Next find plug-in ''org.eclipse.linuxtools.tmf.ui'' and press '''OK'''<br>
405[[Image:images/AddDependencyTmfUi.png]]<br>
406
407Change to the Extensions tab and select '''Add...''' of the ''All Extension'' section. A new dialog box will open. Find the view extension ''org.eclipse.ui.views'' and press '''Finish'''.<br>
408[[Image:images/AddViewExtension1.png]]<br>
409
410To create a Sequence Diagram View, click the right mouse button. Then select '''New -> view'''<br>
411[[Image:images/AddViewExtension2.png]]<br>
412
413A new view entry has been created. Fill in the fields ''id'', ''name'' and ''class''. Note that for ''class'' the SD view implementation (''org.eclipse.linuxtools.tmf.ui.views.SDView'') of the TMF UI plug-in is used.<br>
414[[Image:images/FillSampleSeqDiagram.png]]<br>
415
416The view is prepared. Run the Example. To launch the an Eclipse Application select the ''Overview'' tab and click on '''Launch an Eclipse Application'''<br>
417[[Image:images/RunEclipseApplication.png]]<br>
418
419A new Eclipse application window will show. In the new window go to '''Windows -> Show View -> Other... -> Other -> Sample Sequence Diagram'''.<br>
420[[Image:images/ShowViewOther.png]]<br>
421
422The Sequence Diagram View will open with an blank page.<br>
423[[Image:images/BlankSampleSeqDiagram.png]]<br>
424
425Close the Example Application.
426
427=== Defining the uml2SDLoader Extension ===
428
429After defining the Sequence Diagram View it's time to create the ''uml2SDLoader'' Extension. <br>
430
431Before doing that add a dependency to TMF. For that select '''Add...''' of the ''Required Plug-ins'' section. A new dialog box will open. Next find plug-in ''org.eclipse.linuxtools.tmf'' and press '''OK'''<br>
432[[Image:images/AddDependencyTmf.png]]<br>
433
434To create the loader extension, change to the Extensions tab and select '''Add...''' of the ''All Extension'' section. A new dialog box will open. Find the extension ''org.eclipse.linuxtools.tmf.ui.uml2SDLoader'' and press '''Finish'''.<br>
435[[Image:images/AddTmfUml2SDLoader.png]]<br>
436
437A new 'uml2SDLoader'' extension has been created. Fill in fields ''id'', ''name'', ''class'', ''view'' and ''default''. Use ''default'' equal true for this example. For the view add the id of the Sequence Diagram View of chapter [[#Creating a Sequence Diagram View | Creating a Sequence Diagram View]]. <br>
438[[Image:images/FillSampleLoader.png]]<br>
439
440Then click on ''class'' (see above) to open the new class dialog box. Fill in the relevant fields and select '''Finish'''. <br>
441[[Image:images/NewSampleLoaderClass.png]]<br>
442
443A new Java class will be created which implements the interface ''org.eclipse.linuxtools.tmf.ui.views.uml2sd.load.IUml2SDLoader''.<br>
444
445<pre>
446package org.eclipse.linuxtools.tmf.sample.ui;
447
448import org.eclipse.linuxtools.tmf.ui.views.uml2sd.SDView;
449import org.eclipse.linuxtools.tmf.ui.views.uml2sd.load.IUml2SDLoader;
450
451public class SampleLoader implements IUml2SDLoader {
452
453 public SampleLoader() {
454 // TODO Auto-generated constructor stub
455 }
456
457 @Override
458 public void dispose() {
459 // TODO Auto-generated method stub
460
461 }
462
463 @Override
464 public String getTitleString() {
465 // TODO Auto-generated method stub
466 return null;
467 }
468
469 @Override
470 public void setViewer(SDView arg0) {
471 // TODO Auto-generated method stub
472
473 }
474</pre>
475
476=== Implementing the Loader Class ===
477
478Next is to implement the methods of the IUml2SDLoader interface method. The following code snippet shows how to create the major sequence diagram elements. Please note that no time information is stored.<br>
479
480<pre>
481package org.eclipse.linuxtools.tmf.sample.ui;
482
483import org.eclipse.linuxtools.tmf.ui.views.uml2sd.SDView;
484import org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.AsyncMessage;
485import org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.AsyncMessageReturn;
486import org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.ExecutionOccurrence;
487import org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.Frame;
488import org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.Lifeline;
489import org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.Stop;
490import org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.SyncMessage;
491import org.eclipse.linuxtools.tmf.ui.views.uml2sd.core.SyncMessageReturn;
492import org.eclipse.linuxtools.tmf.ui.views.uml2sd.load.IUml2SDLoader;
493
494public class SampleLoader implements IUml2SDLoader {
495
496 private SDView fSdView;
497
498 public SampleLoader() {
499 }
500
501 @Override
502 public void dispose() {
503 }
504
505 @Override
506 public String getTitleString() {
507 return "Sample Diagram";
508 }
509
510 @Override
511 public void setViewer(SDView arg0) {
512 fSdView = arg0;
513 createFrame();
514 }
515
516 private void createFrame() {
517
518 Frame testFrame = new Frame();
519 testFrame.setName("Sample Frame");
520
521 /*
522 * Create lifelines
523 */
524
525 Lifeline lifeLine1 = new Lifeline();
526 lifeLine1.setName("Object1");
527 testFrame.addLifeLine(lifeLine1);
528
529 Lifeline lifeLine2 = new Lifeline();
530 lifeLine2.setName("Object2");
531 testFrame.addLifeLine(lifeLine2);
532
533
534 /*
535 * Create Sync Message
536 */
537 // Get new occurrence on lifelines
538 lifeLine1.getNewEventOccurrence();
539
540 // Get Sync message instances
541 SyncMessage start = new SyncMessage();
542 start.setName("Start");
543 start.setEndLifeline(lifeLine1);
544 testFrame.addMessage(start);
545
546 /*
547 * Create Sync Message
548 */
549 // Get new occurrence on lifelines
550 lifeLine1.getNewEventOccurrence();
551 lifeLine2.getNewEventOccurrence();
552
553 // Get Sync message instances
554 SyncMessage syn1 = new SyncMessage();
555 syn1.setName("Sync Message 1");
556 syn1.setStartLifeline(lifeLine1);
557 syn1.setEndLifeline(lifeLine2);
558 testFrame.addMessage(syn1);
559
560 /*
561 * Create corresponding Sync Message Return
562 */
563
564 // Get new occurrence on lifelines
565 lifeLine1.getNewEventOccurrence();
566 lifeLine2.getNewEventOccurrence();
567
568 SyncMessageReturn synReturn1 = new SyncMessageReturn();
569 synReturn1.setName("Sync Message Return 1");
570 synReturn1.setStartLifeline(lifeLine2);
571 synReturn1.setEndLifeline(lifeLine1);
572 synReturn1.setMessage(syn1);
573 testFrame.addMessage(synReturn1);
574
575 /*
576 * Create Activations (Execution Occurrence)
577 */
578 ExecutionOccurrence occ1 = new ExecutionOccurrence();
579 occ1.setStartOccurrence(start.getEventOccurrence());
580 occ1.setEndOccurrence(synReturn1.getEventOccurrence());
581 lifeLine1.addExecution(occ1);
582 occ1.setName("Activation 1");
583
584 ExecutionOccurrence occ2 = new ExecutionOccurrence();
585 occ2.setStartOccurrence(syn1.getEventOccurrence());
586 occ2.setEndOccurrence(synReturn1.getEventOccurrence());
587 lifeLine2.addExecution(occ2);
588 occ2.setName("Activation 2");
589
590 /*
591 * Create Sync Message
592 */
593 // Get new occurrence on lifelines
594 lifeLine1.getNewEventOccurrence();
595 lifeLine2.getNewEventOccurrence();
596
597 // Get Sync message instances
598 AsyncMessage asyn1 = new AsyncMessage();
599 asyn1.setName("Async Message 1");
600 asyn1.setStartLifeline(lifeLine1);
601 asyn1.setEndLifeline(lifeLine2);
602 testFrame.addMessage(asyn1);
603
604 /*
605 * Create corresponding Sync Message Return
606 */
607
608 // Get new occurrence on lifelines
609 lifeLine1.getNewEventOccurrence();
610 lifeLine2.getNewEventOccurrence();
611
612 AsyncMessageReturn asynReturn1 = new AsyncMessageReturn();
613 asynReturn1.setName("Async Message Return 1");
614 asynReturn1.setStartLifeline(lifeLine2);
615 asynReturn1.setEndLifeline(lifeLine1);
616 asynReturn1.setMessage(asyn1);
617 testFrame.addMessage(asynReturn1);
618
619 /*
620 * Create a note
621 */
622
623 // Get new occurrence on lifelines
624 lifeLine1.getNewEventOccurrence();
625
626 EllipsisisMessage info = new EllipsisisMessage();
627 info.setName("Object deletion");
628 info.setStartLifeline(lifeLine2);
629 testFrame.addNode(info);
630
631 /*
632 * Create a Stop
633 */
634 Stop stop = new Stop();
635 stop.setLifeline(lifeLine2);
636 stop.setEventOccurrence(lifeLine2.getNewEventOccurrence());
637 lifeLine2.addNode(stop);
638
639 fSdView.setFrame(testFrame);
640 }
641}
642</pre>
643
644Now it's time to run the example application. To launch the Example Application select the ''Overview'' tab and click on '''Launch an Eclipse Application'''<br>
645[[Image:images/SampleDiagram1.png]] <br>
646
647=== Adding time information ===
648
649To add time information in sequence diagram the timestamp has to be set for each message. The sequence diagram framework uses the ''TmfTimestamp'' class of plug-in ''org.eclipse.linuxtools.tmf''. Use ''setTime()'' on each message ''SyncMessage'' since start and end time are the same. For each ''AsyncMessage'' set start and end time separately by using methods ''setStartTime'' and ''setEndTime''. For example: <br>
650
651<pre>
652 private void createFrame() {
653 //...
fac4e45b
BH
654 start.setTime(new TmfTimestamp(1000, -3));
655 syn1.setTime(new TmfTimestamp(1005, -3));
656 synReturn1.setTime(new TmfTimestamp(1050, -3));
657 asyn1.setStartTime(new TmfTimestamp(1060, -3));
658 asyn1.setEndTime(new TmfTimestamp(1070, -3));
659 asynReturn1.setStartTime(new TmfTimestamp(1060, -3));
660 asynReturn1.setEndTime(new TmfTimestamp(1070, -3));
067490ab
AM
661 //...
662 }
663</pre>
664
665When running the example application, a time compression bar on the left appears which indicates the time elapsed between consecutive events. The time compression scale shows where the time falls between the minimum and maximum delta times. The intensity of the color is used to indicate the length of time, namely, the deeper the intensity, the higher the delta time. The minimum and maximum delta times are configurable through the collbar menu ''Configure Min Max''. The time compression bar and scale may provide an indication about which events consumes the most time. By hovering over the time compression bar a tooltip appears containing more information. <br>
666
667[[Image:images/SampleDiagramTimeComp.png]] <br>
668
669By hovering over a message it will show the time information in the appearing tooltip. For each ''SyncMessage'' it shows its time occurrence and for each ''AsyncMessage'' it shows the start and end time.
670
671[[Image:images/SampleDiagramSyncMessage.png]] <br>
672[[Image:images/SampleDiagramAsyncMessage.png]] <br>
673
674To see the time elapsed between 2 messages, select one message and hover over a second message. A tooltip will show with the delta in time. Note if the second message is before the first then a negative delta is displayed. Note that for ''AsynMessage'' the end time is used for the delta calculation.<br>
675[[Image:images/SampleDiagramMessageDelta.png]] <br>
676
677=== Default Coolbar and Menu Items ===
678
679The Sequence Diagram View comes with default coolbar and menu items. By default, each sequence diagram shows the following actions:
680* Zoom in
681* Zoom out
682* Reset Zoom Factor
683* Selection
684* Configure Min Max (drop-down menu only)
685* Navigation -> Show the node end (drop-down menu only)
686* Navigation -> Show the node start (drop-down menu only)
687
688[[Image:images/DefaultCoolbarMenu.png]]<br>
689
690=== Implementing Optional Callbacks ===
691
692The following chapters describe how to use all supported provider interfaces.
693
694==== Using the Paging Provider Interface ====
695
696For scalability reasons, the paging provider interfaces exists to limit the number of messages displayed in the Sequence Diagram View at a time. For that, two interfaces exist, the basic paging provider and the advanced paging provider. When using the basic paging interface, actions for traversing page by page through the sequence diagram of a trace will be provided.
697<br>
698To use the basic paging provider, first the interface methods of the ''ISDPagingProvider'' have to be implemented by a class. (i.e. ''hasNextPage()'', ''hasPrevPage()'', ''nextPage()'', ''prevPage()'', ''firstPage()'' and ''endPage()''. Typically, this is implemented in the loader class. Secondly, the provider has to be set in the Sequence Diagram View. This will be done in the ''setViewer()'' method of the loader class. Lastly, the paging provider has to be removed from the view, when the ''dispose()'' method of the loader class is called.
699
700<pre>
701public class SampleLoader implements IUml2SDLoader, ISDPagingProvider {
702 //...
703 private page = 0;
704
705 @Override
706 public void dispose() {
707 if (fSdView != null) {
708 fSdView.resetProviders();
709 }
710 }
711
712 @Override
713 public void setViewer(SDView arg0) {
714 fSdView = arg0;
715 fSdView.setSDPagingProvider(this);
716 createFrame();
717 }
718
719 private void createSecondFrame() {
720 Frame testFrame = new Frame();
721 testFrame.setName("SecondFrame");
722 Lifeline lifeline = new Lifeline();
723 lifeline.setName("LifeLine 0");
724 testFrame.addLifeLine(lifeline);
725 lifeline = new Lifeline();
726 lifeline.setName("LifeLine 1");
727 testFrame.addLifeLine(lifeline);
728 for (int i = 1; i < 5; i++) {
729 SyncMessage message = new SyncMessage();
730 message.autoSetStartLifeline(testFrame.getLifeline(0));
731 message.autoSetEndLifeline(testFrame.getLifeline(0));
732 message.setName((new StringBuilder("Message ")).append(i).toString());
733 testFrame.addMessage(message);
734
735 SyncMessageReturn messageReturn = new SyncMessageReturn();
736 messageReturn.autoSetStartLifeline(testFrame.getLifeline(0));
737 messageReturn.autoSetEndLifeline(testFrame.getLifeline(0));
738
739 testFrame.addMessage(messageReturn);
740 messageReturn.setName((new StringBuilder("Message return ")).append(i).toString());
741 ExecutionOccurrence occ = new ExecutionOccurrence();
742 occ.setStartOccurrence(testFrame.getSyncMessage(i - 1).getEventOccurrence());
743 occ.setEndOccurrence(testFrame.getSyncMessageReturn(i - 1).getEventOccurrence());
744 testFrame.getLifeline(0).addExecution(occ);
745 }
746 fSdView.setFrame(testFrame);
747 }
748
067490ab
AM
749 @Override
750 public boolean hasNextPage() {
751 return page == 0;
752 }
753
067490ab
AM
754 @Override
755 public boolean hasPrevPage() {
756 return page == 1;
757 }
758
067490ab
AM
759 @Override
760 public void nextPage() {
761 page = 1;
762 createSecondFrame();
763 }
764
067490ab
AM
765 @Override
766 public void prevPage() {
767 page = 0;
768 createFrame();
769 }
770
067490ab
AM
771 @Override
772 public void firstPage() {
773 page = 0;
774 createFrame();
775 }
776
067490ab
AM
777 @Override
778 public void lastPage() {
779 page = 1;
780 createSecondFrame();
781 }
782 //...
783}
784
785</pre>
786
787When running the example application, new actions will be shown in the coolbar and the coolbar menu. <br>
788
789[[Image:images/PageProviderAdded.png]]
790
791<br><br>
792To use the advanced paging provider, the interface ''ISDAdvancePagingProvider'' has to be implemented. It extends the basic paging provider. The methods ''currentPage()'', ''pagesCount()'' and ''pageNumberChanged()'' have to be added.
793<br>
794
795==== Using the Find Provider Interface ====
796
fac4e45b 797For finding nodes in a sequence diagram two interfaces exists. One for basic finding and one for extended finding. The basic find comes with a dialog box for entering find criteria as regular expressions. This find criteria can be used to execute the find. Find criteria a persisted in the Eclipse workspace.
067490ab
AM
798<br>
799For the extended find provider interface a ''org.eclipse.jface.action.Action'' class has to be provided. The actual find handling has to be implemented and triggered by the action.
800<br>
801Only on at a time can be active. If the extended find provder is defined it obsoletes the basic find provider.
802<br>
803To use the basic find provider, first the interface methods of the ''ISDFindProvider'' have to be implemented by a class. Typically, this is implemented in the loader class. Add the ISDFindProvider to the list of implemented interfaces, implement the methods ''find()'' and ''cancel()'' and set the provider in the ''setViewer()'' method as well as remove the provider in the ''dispose()'' method of the loader class. Please note that the ''ISDFindProvider'' extends the interface ''ISDGraphNodeSupporter'' which methods (''isNodeSupported()'' and ''getNodeName()'') have to be implemented, too. The following shows an example implementation. Please note that only search for lifelines and SynchMessage are supported. The find itself will always find only the first occurrence the pattern to match.
804
805<pre>
806public class SampleLoader implements IUml2SDLoader, ISDPagingProvider, ISDFindProvider {
807
808 //...
809 @Override
810 public void dispose() {
811 if (fSdView != null) {
812 fSdView.resetProviders();
813 }
814 }
815
816 @Override
817 public void setViewer(SDView arg0) {
818 fSdView = arg0;
819 fSdView.setSDPagingProvider(this);
820 fSdView.setSDFindProvider(this);
821 createFrame();
822 }
11252342 823
067490ab
AM
824 @Override
825 public boolean isNodeSupported(int nodeType) {
826 switch (nodeType) {
827 case ISDGraphNodeSupporter.LIFELINE:
828 case ISDGraphNodeSupporter.SYNCMESSAGE:
829 return true;
830
831 default:
832 break;
833 }
834 return false;
835 }
836
067490ab
AM
837 @Override
838 public String getNodeName(int nodeType, String loaderClassName) {
839 switch (nodeType) {
840 case ISDGraphNodeSupporter.LIFELINE:
841 return "Lifeline";
842 case ISDGraphNodeSupporter.SYNCMESSAGE:
843 return "Sync Message";
844 }
845 return "";
846 }
847
067490ab
AM
848 @Override
849 public boolean find(Criteria criteria) {
850 Frame frame = fSdView.getFrame();
851 if (criteria.isLifeLineSelected()) {
852 for (int i = 0; i < frame.lifeLinesCount(); i++) {
853 if (criteria.matches(frame.getLifeline(i).getName())) {
854 fSdView.getSDWidget().moveTo(frame.getLifeline(i));
855 return true;
856 }
857 }
858 }
859 if (criteria.isSyncMessageSelected()) {
860 for (int i = 0; i < frame.syncMessageCount(); i++) {
861 if (criteria.matches(frame.getSyncMessage(i).getName())) {
862 fSdView.getSDWidget().moveTo(frame.getSyncMessage(i));
863 return true;
864 }
865 }
866 }
867 return false;
868 }
869
067490ab
AM
870 @Override
871 public void cancel() {
872 // reset find parameters
873 }
874 //...
875}
876</pre>
877
878When running the example application, the find action will be shown in the coolbar and the coolbar menu. <br>
879[[Image:images/FindProviderAdded.png]]
880
881To find a sequence diagram node press on the find button of the coolbar (see above). A new dialog box will open. Enter a regular expression in the ''Matching String'' text box, select the node types (e.g. Sync Message) and press '''Find'''. If found the corresponding node will be selected. If not found the dialog box will indicate not found. <br>
882[[Image:images/FindDialog.png]]<br>
883
884Note that the find dialog will be opened by typing the key shortcut CRTL+F.
885
886==== Using the Filter Provider Interface ====
887
fac4e45b 888For filtering of sequence diagram elements two interfaces exists. One basic for filtering and one for extended filtering. The basic filtering comes with two dialog for entering filter criteria as regular expressions and one for selecting the filter to be used. Multiple filters can be active at a time. Filter criteria are persisted in the Eclipse workspace.
067490ab
AM
889<br>
890To use the basic filter provider, first the interface method of the ''ISDFilterProvider'' has to be implemented by a class. Typically, this is implemented in the loader class. Add the ''ISDFilterProvider'' to the list of implemented interfaces, implement the method ''filter()''and set the provider in the ''setViewer()'' method as well as remove the provider in the ''dispose()'' method of the loader class. Please note that the ''ISDFindProvider'' extends the interface ''ISDGraphNodeSupporter'' which methods (''isNodeSupported()'' and ''getNodeName()'') have to be implemented, too. <br>
891Note that no example implementation of ''filter()'' is provided.
892<br>
893
894<pre>
895public class SampleLoader implements IUml2SDLoader, ISDPagingProvider, ISDFindProvider, ISDFilterProvider {
896
897 //...
898 @Override
899 public void dispose() {
900 if (fSdView != null) {
901 fSdView.resetProviders();
902 }
903 }
904
905 @Override
906 public void setViewer(SDView arg0) {
907 fSdView = arg0;
908 fSdView.setSDPagingProvider(this);
909 fSdView.setSDFindProvider(this);
910 fSdView.setSDFilterProvider(this);
911 createFrame();
912 }
913
067490ab
AM
914 @Override
915 public boolean filter(List<?> list) {
916 return false;
917 }
918 //...
919}
920</pre>
921
922When running the example application, the filter action will be shown in the coolbar menu. <br>
923[[Image:images/HidePatternsMenuItem.png]]
924
925To filter select the '''Hide Patterns...''' of the coolbar menu. A new dialog box will open. <br>
926[[Image:images/DialogHidePatterns.png]]
927
928To Add a new filter press '''Add...'''. A new dialog box will open. Enter a regular expression in the ''Matching String'' text box, select the node types (e.g. Sync Message) and press '''Create''''. <br>
929[[Image:images/DialogHidePatterns.png]] <br>
930
931Now back at the Hide Pattern dialog. Select one or more filter and select '''OK'''.
932
933To use the extended filter provider, the interface ''ISDExtendedFilterProvider'' has to be implemented. It will provide a ''org.eclipse.jface.action.Action'' class containing the actual filter handling and filter algorithm.
934
935==== Using the Extended Action Bar Provider Interface ====
936
937The extended action bar provider can be used to add customized actions to the Sequence Diagram View.
938To use the extended action bar provider, first the interface method of the interface ''ISDExtendedActionBarProvider'' has to be implemented by a class. Typically, this is implemented in the loader class. Add the ''ISDExtendedActionBarProvider'' to the list of implemented interfaces, implement the method ''supplementCoolbarContent()'' and set the provider in the ''setViewer()'' method as well as remove the provider in the ''dispose()'' method of the loader class. <br>
939
940<pre>
941public class SampleLoader implements IUml2SDLoader, ISDPagingProvider, ISDFindProvider, ISDFilterProvider, ISDExtendedActionBarProvider {
942 //...
943
944 @Override
945 public void dispose() {
946 if (fSdView != null) {
947 fSdView.resetProviders();
948 }
949 }
950
951 @Override
952 public void setViewer(SDView arg0) {
953 fSdView = arg0;
954 fSdView.setSDPagingProvider(this);
955 fSdView.setSDFindProvider(this);
956 fSdView.setSDFilterProvider(this);
957 fSdView.setSDExtendedActionBarProvider(this);
958 createFrame();
959 }
960
067490ab
AM
961 @Override
962 public void supplementCoolbarContent(IActionBars iactionbars) {
963 Action action = new Action("Refresh") {
964 @Override
965 public void run() {
966 System.out.println("Refreshing...");
967 }
968 };
969 iactionbars.getMenuManager().add(action);
970 iactionbars.getToolBarManager().add(action);
971 }
972 //...
973}
974</pre>
975
976When running the example application, all new actions will be added to the coolbar and coolbar menu according to the implementation of ''supplementCoolbarContent()''<br>.
977For the example above the coolbar and coolbar menu will look as follows.
978
979[[Image:images/SupplCoolbar.png]]
980
981==== Using the Properties Provider Interface====
982
983This interface can be used to provide property information. A property provider which returns an ''IPropertyPageSheet'' (see ''org.eclipse.ui.views'') has to be implemented and set in the Sequence Diagram View. <br>
984
985To use the property provider, first the interface method of the ''ISDPropertiesProvider'' has to be implemented by a class. Typically, this is implemented in the loader class. Add the ''ISDPropertiesProvider'' to the list of implemented interfaces, implement the method ''getPropertySheetEntry()'' and set the provider in the ''setViewer()'' method as well as remove the provider in the ''dispose()'' method of the loader class. Please note that no example is provided here.
986
987Please refer to the following Eclipse articles for more information about properties and tabed properties.
988*[http://www.eclipse.org/articles/Article-Properties-View/properties-view.html | Take control of your properties]
989*[http://www.eclipse.org/articles/Article-Tabbed-Properties/tabbed_properties_view.html | The Eclipse Tabbed Properties View]
990
991==== Using the Collapse Provider Interface ====
992
993This interface can be used to define a provider which responsibility is to collapse two selected lifelines. This can be used to hide a pair of lifelines.
994
995To use the collapse provider, first the interface method of the ''ISDCollapseProvider'' has to be implemented by a class. Typically, this is implemented in the loader class. Add the ISDCollapseProvider to the list of implemented interfaces, implement the method ''collapseTwoLifelines()'' and set the provider in the ''setViewer()'' method as well as remove the provider in the ''dispose()'' method of the loader class. Please note that no example is provided here.
996
997==== Using the Selection Provider Service ====
998
999The Sequence Diagram View comes with a build in selection provider service. To this service listeners can be added. To use the selection provider service, the interface ''ISelectionListener'' of plug-in ''org.eclipse.ui'' has to implemented. Typically this is implemented in loader class. Firstly, add the ''ISelectionListener'' interface to the list of implemented interfaces, implement the method ''selectionChanged()'' and set the listener in method ''setViewer()'' as well as remove the listener in the ''dispose()'' method of the loader class.
1000
1001<pre>
1002public class SampleLoader implements IUml2SDLoader, ISDPagingProvider, ISDFindProvider, ISDFilterProvider, ISDExtendedActionBarProvider, ISelectionListener {
1003
1004 //...
1005 @Override
1006 public void dispose() {
1007 if (fSdView != null) {
1008 PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService().removePostSelectionListener(this);
1009 fSdView.resetProviders();
1010 }
1011 }
1012
1013 @Override
1014 public String getTitleString() {
1015 return "Sample Diagram";
1016 }
1017
1018 @Override
1019 public void setViewer(SDView arg0) {
1020 fSdView = arg0;
1021 PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService().addPostSelectionListener(this);
1022 fSdView.setSDPagingProvider(this);
1023 fSdView.setSDFindProvider(this);
1024 fSdView.setSDFilterProvider(this);
1025 fSdView.setSDExtendedActionBarProvider(this);
1026
1027 createFrame();
1028 }
1029
067490ab
AM
1030 @Override
1031 public void selectionChanged(IWorkbenchPart part, ISelection selection) {
1032 ISelection sel = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService().getSelection();
1033 if (sel != null && (sel instanceof StructuredSelection)) {
1034 StructuredSelection stSel = (StructuredSelection) sel;
1035 if (stSel.getFirstElement() instanceof BaseMessage) {
1036 BaseMessage syncMsg = ((BaseMessage) stSel.getFirstElement());
1037 System.out.println("Message '" + syncMsg.getName() + "' selected.");
1038 }
1039 }
1040 }
1041
1042 //...
1043}
1044</pre>
1045
1046=== Printing a Sequence Diagram ===
1047
1048To print a the whole sequence diagram or only parts of it, select the Sequence Diagram View and select '''File -> Print...''' or type the key combination ''CTRL+P''. A new print dialog will open. <br>
1049
1050[[Image:images/PrintDialog.png]] <br>
1051
1052Fill in all the relevant information, select '''Printer...''' to choose the printer and the press '''OK'''.
1053
1054=== Using one Sequence Diagram View with Multiple Loaders ===
1055
1056A Sequence Diagram View definition can be used with multiple sequence diagram loaders. However, the active loader to be used when opening the view has to be set. For this define an Eclipse action or command and assign the current loader to the view. Here is a code snippet for that:
1057
1058<pre>
1059public class OpenSDView extends AbstractHandler {
1060 @Override
1061 public Object execute(ExecutionEvent event) throws ExecutionException {
1062 try {
1063 IWorkbenchPage persp = TmfUiPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage();
1064 SDView view = (SDView) persp.showView("org.eclipse.linuxtools.ust.examples.ui.componentinteraction");
1065 LoadersManager.getLoadersManager().createLoader("org.eclipse.linuxtools.tmf.ui.views.uml2sd.impl.TmfUml2SDSyncLoader", view);
1066 } catch (PartInitException e) {
1067 throw new ExecutionException("PartInitException caught: ", e);
1068 }
1069 return null;
1070 }
1071}
1072</pre>
1073
1074=== Downloading the Tutorial ===
1075
fac4e45b 1076Use the following link to download the source code of the tutorial [http://wiki.eclipse.org/images/e/e6/SamplePlugin.zip Plug-in of Tutorial].
067490ab
AM
1077
1078== Integration of Tracing and Monitoring Framework with Sequence Diagram Framework ==
1079
1080In the previous sections the Sequence Diagram Framework has been described and a tutorial was provided. In the following sections the integration of the Sequence Diagram Framework with other features of TMF will be described. Together it is a powerful framework to analyze and visualize content of traces. The integration is explained using the reference implementation of a UML2 sequence diagram loader which part of the TMF UI delivery. The reference implementation can be used as is, can be sub-classed or simply be an example for other sequence diagram loaders to be implemented.
1081
1082=== Reference Implementation ===
1083
1084A Sequence Diagram View Extension is defined in the plug-in TMF UI as well as a uml2SDLoader Extension with the reference loader.
1085
1086[[Image:images/ReferenceExtensions.png]]
1087
1088=== Used Sequence Diagram Features ===
1089
1090Besides the default features of the Sequence Diagram Framework, the reference implementation uses the following additional features:
1091*Advanced paging
1092*Basic finding
1093*Basic filtering
1094*Selection Service
1095
1096==== Advanced paging ====
1097
1098The reference loader implements the interface ''ISDAdvancedPagingProvider'' interface. Please refer to section [[#Using the Paging Provider Interface | Using the Paging Provider Interface]] for more details about the advanced paging feature.
1099
1100==== Basic finding ====
1101
1102The reference loader implements the interface ''ISDFindProvider'' interface. The user can search for ''Lifelines'' and ''Interactions''. The find is done across pages. If the expression to match is not on the current page a new thread is started to search on other pages. If expression is found the corresponding page is shown as well as the searched item is displayed. If not found then a message is displayed in the ''Progress View'' of Eclipse. Please refer to section [[#Using the Find Provider Interface | Using the Find Provider Interface]] for more details about the basic find feature.
1103
1104==== Basic filtering ====
1105
1106The reference loader implements the interface ''ISDFilterProvider'' interface. The user can filter on ''Lifelines'' and ''Interactions''. Please refer to section [[#Using the Filter Provider Interface | Using the Filter Provider Interface]] for more details about the basic filter feature.
1107
1108==== Selection Service ====
1109
1110The reference loader implements the interface ''ISelectionListener'' interface. When an interaction is selected a ''TmfTimeSynchSignal'' is broadcast (see [[#TMF Signal Framework | TMF Signal Framework]]). Please also refer to section [[#Using the Selection Provider Service | Using the Selection Provider Service]] for more details about the selection service and .
1111
1112=== Used TMF Features ===
1113
1114The reference implementation uses the following features of TMF:
1115*TMF Experiment and Trace for accessing traces
1116*Event Request Framework to request TMF events from the experiment and respective traces
1117*Signal Framework for broadcasting and receiving TMF signals for synchronization purposes
1118
1119==== TMF Experiment and Trace for accessing traces ====
1120
1121The reference loader uses TMF Experiments to access traces and to request data from the traces.
1122
1123==== TMF Event Request Framework ====
1124
1125The reference loader use the TMF Event Request Framework to request events from the experiment and its traces.
1126
1127When opening a traces (which is triggered by signal ''TmfExperimentSelected'') or when opening the Sequence Diagram View after a trace had been opened previously, a TMF background request is initiated to index the trace and to fill in the first page of the sequence diagram. The purpose of the indexing is to store time ranges for pages with 10000 messages per page. This allows quickly to move to certain pages in a trace without having to re-parse from the beginning. The request is called indexing request.
1128
1129When switching pages, the a TMF foreground event request is initiated to retrieve the corresponding events from the experiment. It uses the time range stored in the index for the respective page.
1130
1131A third type of event request is issued for finding specific data across pages.
1132
1133==== TMF Signal Framework ====
1134
1135The reference loader extends the class ''TmfComponent''. By doing that the loader is register as TMF signal handler for sending and receiving TMF signals. The loader implements signal handlers for the following TMF signals:
fac4e45b
BH
1136*''TmfTraceSelectedSignal''
1137This signal indicates that a trace or experiment was selected. When receiving this signal the indexing request is initiated and the first page is displayed after receiving the relevant information.
1138*''traceClosed''
1139This signal indicates that a trace or experiment was closed. When receiving this signal the loader resets its data and a blank page is loaded in the Sequence Diagram View.
067490ab 1140*''TmfTimeSynchSignal''
fac4e45b 1141This signal indicates that a event with a certain timestamp is selected. When receiving this signal the corresponding message is selected in the Sequence Diagram View. If necessary, the page is changed.
067490ab
AM
1142*''TmfRangeSynchSignal''
1143This signal indicates that a new time range is in focus. When receiving this signal the loader loads the page which corresponds to the start time of the time range signal. The message with the start time will be in focus.
1144
fac4e45b 1145Besides acting on receiving signals, the reference loader is also sending signals. A ''TmfTimeSynchSignal'' is broadcasted with the timestamp of the message which was selected in the Sequence Diagram View. ''TmfRangeSynchSignal'' is sent when a page is changed in the Sequence Diagram View. The start timestamp of the time range sent is the timestamp of the first message. The end timestamp sent is the timestamp of the first message plus the current time range window. The current time range window is the time window that was indicated in the last received ''TmfRangeSynchSignal''.
067490ab
AM
1146
1147=== Supported Traces ===
1148
fac4e45b 1149The reference implementation is able to analyze traces from a single component that traces the interaction with other components. For example, a server node could have trace information about its interaction with client nodes. The server node could be traced and then analyzed using TMF and the Sequence Diagram Framework of TMF could used to visualize the interactions with the client nodes.<br>
067490ab
AM
1150
1151Note that combined traces of multiple components, that contain the trace information about the same interactions are not supported in the reference implementation!
1152
1153=== Trace Format ===
1154
1155The reference implementation in class ''TmfUml2SDSyncLoader'' in package ''org.eclipse.linuxtools.tmf.ui.views.uml2sd.impl'' analyzes events from type ''ITmfEvent'' and creates events type ''ITmfSyncSequenceDiagramEvent'' if the ''ITmfEvent'' contains all relevant information information. The parsing algorithm looks like as follows:
1156
1157<pre>
1158 /**
1159 * @param tmfEvent Event to parse for sequence diagram event details
1160 * @return sequence diagram event if details are available else null
1161 */
fac4e45b 1162 protected ITmfSyncSequenceDiagramEvent getSequenceDiagramEvent(ITmfEvent tmfEvent){
067490ab
AM
1163 //type = .*RECEIVE.* or .*SEND.*
1164 //content = sender:<sender name>:receiver:<receiver name>,signal:<signal name>
1165 String eventType = tmfEvent.getType().toString();
fac4e45b
BH
1166 if (eventType.contains(Messages.TmfUml2SDSyncLoader_EventTypeSend) || eventType.contains(Messages.TmfUml2SDSyncLoader_EventTypeReceive)) {
1167 Object sender = tmfEvent.getContent().getField(Messages.TmfUml2SDSyncLoader_FieldSender);
1168 Object receiver = tmfEvent.getContent().getField(Messages.TmfUml2SDSyncLoader_FieldReceiver);
1169 Object name = tmfEvent.getContent().getField(Messages.TmfUml2SDSyncLoader_FieldSignal);
067490ab
AM
1170 if ((sender instanceof ITmfEventField) && (receiver instanceof ITmfEventField) && (name instanceof ITmfEventField)) {
1171 ITmfSyncSequenceDiagramEvent sdEvent = new TmfSyncSequenceDiagramEvent(tmfEvent,
1172 ((ITmfEventField) sender).getValue().toString(),
1173 ((ITmfEventField) receiver).getValue().toString(),
1174 ((ITmfEventField) name).getValue().toString());
1175
1176 return sdEvent;
1177 }
1178 }
1179 return null;
fac4e45b 1180 }
067490ab
AM
1181</pre>
1182
1183The analysis looks for event type Strings containing ''SEND'' and ''RECEIVE''. If event type matches these key words, the analyzer will look for strings ''sender'', ''receiver'' and ''signal'' in the event fields of type ''ITmfEventField''. If all the data is found a sequence diagram event from can be created. Note that Sync Messages are assumed, which means start and end time are the same.
1184
1185=== How to use the Reference Implementation ===
1186
1187An example trace visualizer is provided that uses a trace in binary format. It contains trace events with sequence diagram information. To parse the data using TMF a class is provided that implements ''ITmfTrace''. Additionally, a parser is provided that reads from the file and converts a trace event to ''TmfEvent''. This parser implements the interface ''ITmfEventParser''. To get the source code see [[#Downloading the Reference Plug-in | Download the Reference Plug-in]]
1188<br>
1189The plug-in structure will look like this:<br>
1190[[Image:images/ReferencePlugin.png]]<br>
1191
1192To open the plug-in manifest, double-click on the MANIFEST.MF file. <br>
1193[[Image:images/SelectManifestRef.png]]<br>
1194
1195Run the Reference Application. To launch the Eclipse Application select the ''Overview'' tab and click on '''Launch an Eclipse Application'''<br>
1196[[Image:images/RunApplicationRef.png]]<br>
1197
1198To open the Reference Sequence Diagram View, select '''Windows -> Show View -> Other... -> TMF -> Sequence Diagram''' <br>
1199[[Image:images/ShowTmfSDView.png]]<br>
1200
fac4e45b 1201An blank Sequence Diagram View will open.
067490ab 1202
fac4e45b 1203Select the '''Select Experiment''' button of the toolbar to load the sequence diagram from the data provided in the trace file. What this does is open the file ''tracesets/sdEvents'', parse this file through TMF and analyze all events of type ''TmfEvent'' and generates the Sequence Diagram out of it. <br>
067490ab
AM
1204[[Image:images/ReferenceSeqDiagram.png]]<br>
1205
1206Now the reference application can be explored. To demonstrate the view features try the following things:
1207*Select a message in the Sequence diagram. As result the corresponding event will be selected in the Events View.
1208*Select an event in the Events View. As result the corresponding message in the Sequence Diagram View will be selected. If necessary, the page will be changed.
1209*In the Events View, press key ''End''. As result, the Sequence Diagram view will jump to the last page.
1210*In the Events View, press key ''Home''. As result, the Sequence Diagram view will jump to the first page.
1211*In the Sequence Diagram View select the find button. Enter the expression '''REGISTER.*''', select '''Search for Interaction''' and press '''Find'''. As result the corresponding message will be selected in the Sequence Diagram and the corresponding event in the Events View will be selected. Select again '''Find''' the next occurrence of will be selected. Since the second occurrence is on a different page than the first, the corresponding page will be loaded.
1212* In the Sequence Diagram View, select menu item '''Hide Patterns...'''. Add the filter '''BALL.*''' for '''Interaction''' only and select '''OK'''. As result all messages with name ''BALL_REQUEST'' and ''BALL_REPLY'' will be hidden. To remove the filter, select menu item '''Hide Patterns...''', deselect the corresponding filter and press '''OK'''. All the messages will be shown again.<br>
1213
1214To dispose the diagram, select the '''Dispose Experiment''' button of the toolbar. The current sequence diagram will be disposed and an empty diagram will be loaded.
1215
1216=== Extending the Reference Loader ===
1217
1218In some case it might be necessary to change the implementation of the analysis of each ''TmfEvent'' for the generation of ''Sequence Diagram Events''. For that just extend the class ''TmfUml2SDSyncLoader'' and overwrite the method ''protected ITmfSyncSequenceDiagramEvent getSequnceDiagramEvent(TmfEvent tmfEvent)'' with your own implementation.
1219
1220=== Downloading the Reference Plug-in ===
fac4e45b 1221To download the reference plug-in that demonstrates the reference loader, use the following link: [http://wiki.eclipse.org/images/d/d3/ReferencePlugin.zip Reference Plug-in]. Just extract the zip file and import the extracted Eclipse plug-in (plug-in name: ''org.eclipse.linuxtools.tmf.reference.ui'') to your Eclipse workspace. <br>
067490ab 1222
f5b8868d
MAL
1223= View Tutorial =
1224
1225This tutorial describes how to create a simple view using the TMF framework and the SWTChart library. SWTChart is a library based on SWT that can draw several types of charts including a line chart which we will use in this tutorial. We will create a view containing a line chart that displays time stamps on the X axis and the corresponding event values on the Y axis.
1226
1227This tutorial will cover concepts like:
1228
1229* Extending TmfView
1230* Signal handling (@TmfSignalHandler)
1231* Data requests (TmfEventRequest)
1232* SWTChart integration
1233
1234=== Prerequisites ===
1235
1236The tutorial is based on Eclipse 4.3 (Eclipse Kepler), TMF 2.0.0 and SWTChart 0.7.0. You can install SWTChart by using the Orbit update site. http://download.eclipse.org/tools/orbit/downloads/
1237
1238=== Creating an Eclipse UI Plug-in ===
1239
1240To create a new project with name org.eclipse.linuxtools.tmf.sample.ui select '''File -> New -> Project -> Plug-in Development -> Plug-in Project'''. <br>
1241[[Image:images/Screenshot-NewPlug-inProject1.png]]<br>
1242
1243[[Image:images/Screenshot-NewPlug-inProject2.png]]<br>
1244
1245[[Image:images/Screenshot-NewPlug-inProject3.png]]<br>
1246
1247=== Creating a View ===
1248
1249To open the plug-in manifest, double-click on the MANIFEST.MF file. <br>
1250[[Image:images/SelectManifest.png]]<br>
1251
1252Change to the Dependencies tab and select '''Add...''' of the ''Required Plug-ins'' section. A new dialog box will open. Next find plug-in ''org.eclipse.linuxtools.tmf.core'' and press '''OK'''<br>
1253Following the same steps, add ''org.eclipse.linuxtools.tmf.ui'' and ''org.swtchart''.<br>
1254[[Image:images/AddDependencyTmfUi.png]]<br>
1255
1256Change to the Extensions tab and select '''Add...''' of the ''All Extension'' section. A new dialog box will open. Find the view extension ''org.eclipse.ui.views'' and press '''Finish'''.<br>
1257[[Image:images/AddViewExtension1.png]]<br>
1258
1259To create a view, click the right mouse button. Then select '''New -> view'''<br>
1260[[Image:images/AddViewExtension2.png]]<br>
1261
1262A new view entry has been created. Fill in the fields ''id'' and ''name''. For ''class'' click on the '''class hyperlink''' and it will show the New Java Class dialog. Enter the name ''SampleView'', change the superclass to ''TmfView'' and click Finish. This will create the source file and fill the ''class'' field in the process. We use TmfView as the superclass because it provides extra functionality like getting the active trace, pinning and it has support for signal handling between components.<br>
1263[[Image:images/FillSampleViewExtension.png]]<br>
1264
1265This will generate an empty class. Once the quick fixes are applied, the following code is obtained:
1266
1267<pre>
1268package org.eclipse.linuxtools.tmf.sample.ui;
1269
1270import org.eclipse.swt.widgets.Composite;
1271import org.eclipse.ui.part.ViewPart;
1272
1273public class SampleView extends TmfView {
1274
1275 public SampleView(String viewName) {
1276 super(viewName);
1277 // TODO Auto-generated constructor stub
1278 }
1279
1280 @Override
1281 public void createPartControl(Composite parent) {
1282 // TODO Auto-generated method stub
1283
1284 }
1285
1286 @Override
1287 public void setFocus() {
1288 // TODO Auto-generated method stub
1289
1290 }
1291
1292}
1293</pre>
1294
1295This creates an empty view, however the basic structure is now is place.
1296
1297===Implementing a view===
1298
1299We will start by adding a empty chart then it will need to be populated with the trace data. Finally, we will make the chart more visually pleasing by adjusting the range and formating the time stamps.
1300
1301====Adding an Empty Chart====
1302
1303First, we can add an empty chart to the view and initialize some of its components.
1304
1305<pre>
1306 private static final String SERIES_NAME = "Series";
1307 private static final String Y_AXIS_TITLE = "Signal";
1308 private static final String X_AXIS_TITLE = "Time";
1309 private static final String FIELD = "value"; // The name of the field that we want to display on the Y axis
1310 private static final String VIEW_ID = "org.eclipse.linuxtools.tmf.sample.ui.view";
1311 private Chart chart;
1312 private ITmfTrace currentTrace;
1313
1314 public SampleView() {
1315 super(VIEW_ID);
1316 }
1317
1318 @Override
1319 public void createPartControl(Composite parent) {
1320 chart = new Chart(parent, SWT.BORDER);
1321 chart.getTitle().setVisible(false);
1322 chart.getAxisSet().getXAxis(0).getTitle().setText(X_AXIS_TITLE);
1323 chart.getAxisSet().getYAxis(0).getTitle().setText(Y_AXIS_TITLE);
1324 chart.getSeriesSet().createSeries(SeriesType.LINE, SERIES_NAME);
1325 chart.getLegend().setVisible(false);
1326 }
1327
1328 @Override
1329 public void setFocus() {
1330 chart.setFocus();
1331 }
1332</pre>
1333
1334The view is prepared. Run the Example. To launch the an Eclipse Application select the ''Overview'' tab and click on '''Launch an Eclipse Application'''<br>
1335[[Image:images/RunEclipseApplication.png]]<br>
1336
1337A new Eclipse application window will show. In the new window go to '''Windows -> Show View -> Other... -> Other -> Sample View'''.<br>
1338[[Image:images/ShowViewOther.png]]<br>
1339
1340You should now see a view containing an empty chart<br>
1341[[Image:images/EmptySampleView.png]]<br>
1342
1343====Signal Handling====
1344
1345We would like to populate the view when a trace is selected. To achieve this, we can use a signal hander which is specified with the '''@TmfSignalHandler''' annotation.
1346
1347<pre>
1348 @TmfSignalHandler
1349 public void traceSelected(final TmfTraceSelectedSignal signal) {
1350
1351 }
1352</pre>
1353
1354====Requesting Data====
1355
1356Then we need to actually gather data from the trace. This is done asynchronously using a ''TmfEventRequest''
1357
1358<pre>
1359 @TmfSignalHandler
1360 public void traceSelected(final TmfTraceSelectedSignal signal) {
1361 // Don't populate the view again if we're already showing this trace
1362 if (currentTrace == signal.getTrace()) {
1363 return;
1364 }
1365 currentTrace = signal.getTrace();
1366
1367 // Create the request to get data from the trace
1368
1369 TmfEventRequest req = new TmfEventRequest(TmfEvent.class,
1370 TmfTimeRange.ETERNITY, TmfEventRequest.ALL_DATA,
1371 ExecutionType.BACKGROUND) {
1372
1373 @Override
1374 public void handleData(ITmfEvent data) {
1375 // Called for each event
1376 super.handleData(data);
1377 }
1378
1379 @Override
1380 public void handleSuccess() {
1381 // Request successful, not more data available
1382 super.handleSuccess();
1383 }
1384
1385 @Override
1386 public void handleFailure() {
1387 // Request failed, not more data available
1388 super.handleFailure();
1389 }
1390 };
1391 ITmfTrace trace = signal.getTrace();
1392 trace.sendRequest(req);
1393 }
1394</pre>
1395
1396====Transferring Data to the Chart====
1397
1398The chart expects an array of doubles for both the X and Y axis values. To provide that, we can accumulate each event's time and value in their respective list then convert the list to arrays when all events are processed.
1399
1400<pre>
1401 TmfEventRequest req = new TmfEventRequest(TmfEvent.class,
1402 TmfTimeRange.ETERNITY, TmfEventRequest.ALL_DATA,
1403 ExecutionType.BACKGROUND) {
1404
1405 ArrayList<Double> xValues = new ArrayList<Double>();
1406 ArrayList<Double> yValues = new ArrayList<Double>();
1407
1408 @Override
1409 public void handleData(ITmfEvent data) {
1410 // Called for each event
1411 super.handleData(data);
1412 ITmfEventField field = data.getContent().getField(FIELD);
1413 if (field != null) {
1414 yValues.add((Double) field.getValue());
1415 xValues.add((double) data.getTimestamp().getValue());
1416 }
1417 }
1418
1419 @Override
1420 public void handleSuccess() {
1421 // Request successful, not more data available
1422 super.handleSuccess();
1423
1424 final double x[] = toArray(xValues);
1425 final double y[] = toArray(yValues);
1426
1427 // This part needs to run on the UI thread since it updates the chart SWT control
1428 Display.getDefault().asyncExec(new Runnable() {
1429
1430 @Override
1431 public void run() {
1432 chart.getSeriesSet().getSeries()[0].setXSeries(x);
1433 chart.getSeriesSet().getSeries()[0].setYSeries(y);
1434
1435 chart.redraw();
1436 }
1437
1438 });
1439 }
1440
1441 /**
1442 * Convert List<Double> to double[]
1443 */
1444 private double[] toArray(List<Double> list) {
1445 double[] d = new double[list.size()];
1446 for (int i = 0; i < list.size(); ++i) {
1447 d[i] = list.get(i);
1448 }
1449
1450 return d;
1451 }
1452 };
1453</pre>
1454
1455====Adjusting the Range====
1456
1457The chart now contains values but they might be out of range and not visible. We can adjust the range of each axis by computing the minimum and maximum values as we add events.
1458
1459<pre>
1460
1461 ArrayList<Double> xValues = new ArrayList<Double>();
1462 ArrayList<Double> yValues = new ArrayList<Double>();
1463 private double maxY = -Double.MAX_VALUE;
1464 private double minY = Double.MAX_VALUE;
1465 private double maxX = -Double.MAX_VALUE;
1466 private double minX = Double.MAX_VALUE;
1467
1468 @Override
1469 public void handleData(ITmfEvent data) {
1470 super.handleData(data);
1471 ITmfEventField field = data.getContent().getField(FIELD);
1472 if (field != null) {
1473 Double yValue = (Double) field.getValue();
1474 minY = Math.min(minY, yValue);
1475 maxY = Math.max(maxY, yValue);
1476 yValues.add(yValue);
1477
1478 double xValue = (double) data.getTimestamp().getValue();
1479 xValues.add(xValue);
1480 minX = Math.min(minX, xValue);
1481 maxX = Math.max(maxX, xValue);
1482 }
1483 }
1484
1485 @Override
1486 public void handleSuccess() {
1487 super.handleSuccess();
1488 final double x[] = toArray(xValues);
1489 final double y[] = toArray(yValues);
1490
1491 // This part needs to run on the UI thread since it updates the chart SWT control
1492 Display.getDefault().asyncExec(new Runnable() {
1493
1494 @Override
1495 public void run() {
1496 chart.getSeriesSet().getSeries()[0].setXSeries(x);
1497 chart.getSeriesSet().getSeries()[0].setYSeries(y);
1498
1499 // Set the new range
1500 if (!xValues.isEmpty() && !yValues.isEmpty()) {
1501 chart.getAxisSet().getXAxis(0).setRange(new Range(0, x[x.length - 1]));
1502 chart.getAxisSet().getYAxis(0).setRange(new Range(minY, maxY));
1503 } else {
1504 chart.getAxisSet().getXAxis(0).setRange(new Range(0, 1));
1505 chart.getAxisSet().getYAxis(0).setRange(new Range(0, 1));
1506 }
1507 chart.getAxisSet().adjustRange();
1508
1509 chart.redraw();
1510 }
1511 });
1512 }
1513</pre>
1514
1515====Formatting the Time Stamps====
1516
1517To display the time stamps on the X axis nicely, we need to specify a format or else the time stamps will be displayed as ''long''. We use TmfTimestampFormat to make it consistent with the other TMF views. We also need to handle the '''TmfTimestampFormatUpdateSignal''' to make sure that the time stamps update when the preferences change.
1518
1519<pre>
1520 @Override
1521 public void createPartControl(Composite parent) {
1522 ...
1523
1524 chart.getAxisSet().getXAxis(0).getTick().setFormat(new TmfChartTimeStampFormat());
1525 }
1526
1527 public class TmfChartTimeStampFormat extends SimpleDateFormat {
1528 private static final long serialVersionUID = 1L;
1529 @Override
1530 public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
1531 long time = date.getTime();
1532 toAppendTo.append(TmfTimestampFormat.getDefaulTimeFormat().format(time));
1533 return toAppendTo;
1534 }
1535 }
1536
1537 @TmfSignalHandler
1538 public void timestampFormatUpdated(TmfTimestampFormatUpdateSignal signal) {
1539 // Called when the time stamp preference is changed
1540 chart.getAxisSet().getXAxis(0).getTick().setFormat(new TmfChartTimeStampFormat());
1541 chart.redraw();
1542 }
1543</pre>
1544
1545We also need to populate the view when a trace is already selected and the view is opened. We can reuse the same code by having the view send the '''TmfTraceSelectedSignal''' to itself.
1546
1547<pre>
1548 @Override
1549 public void createPartControl(Composite parent) {
1550 ...
1551
1552 ITmfTrace trace = getActiveTrace();
1553 if (trace != null) {
1554 traceSelected(new TmfTraceSelectedSignal(this, trace));
1555 }
1556 }
1557</pre>
1558
1559The view is now ready but we need a proper trace to test it. For this example, a trace was generated using LTTng-UST so that it would produce a sine function.<br>
1560
1561[[Image:images/SampleView.png]]<br>
1562
1563In summary, we have implemented a simple TMF view using the SWTChart library. We made use of signals and requests to populate the view at the appropriate time and we formated the time stamps nicely. We also made sure that the time stamp format is updated when the preferences change.
1564
2819a797
MK
1565
1566=Implementing a New Trace Type=
1567
1568The framework can easily be extended to support more trace types. To make a new trace type, one must define the following items:
1569
1570* The event type
1571* The trace reader
1572* The trace context
1573* The trace location
1574* (Optional but recommended) The ''org.eclipse.linuxtools.tmf.ui.tracetype'' plug-in extension point
1575
1576The '''event type''' must implement an ''ITmfEvent'' or extend a class that implements an ''ITmfEvent''. Typically it will extend ''TmfEvent''. The event type must contain all the data of an event. The '''trace reader''' must be of an ''ITmfTrace'' type. The ''TmfTrace'' class will supply many background operations so that the reader only needs to implement certain functions. The '''trace context''' can be seen as the internals of an iterator. It is required by the trace reader to parse events as it iterates the trace and to keep track of its rank and location. It can have a timestamp, a rank, a file position, or any other element, it should be considered to be ephemeral. The '''trace location''' is an element that is cloned often to store checkpoints, it is generally persistent. It is used to rebuild a context, therefore, it needs to contain enough information to unambiguously point to one and only one event. Finally the ''tracetype'' plug-in extension associates a given trace, non-programmatically to a trace type for use in the UI.
1577
1578==An Example: Nexus-lite parser==
1579
1580===Description of the file===
1581
1582This is a very small subset of the nexus trace format, with some changes to make it easier to read. There is one file. This file starts with 64 Strings containing the event names, then an arbitrarily large number of events. The events are each 64 bits long. the first 32 are the timestamp in microseconds, the second 32 are split into 6 bits for the event type, and 26 for the data payload.
1583
1584The trace type will be made of two parts, part 1 is the event description, it is just 64 strings, comma seperated and then a line feed.
1585
1586<pre>
1587Startup,Stop,Load,Add, ... ,reserved\n
1588</pre>
1589
1590Then there will be the events in this format
1591
1592{| width= "85%"
1593|style="width: 50%; background-color: #ffffcc;"|timestamp (32 bits)
1594|style="width: 10%; background-color: #ffccff;"|type (6 bits)
1595|style="width: 40%; background-color: #ccffcc;"|payload (26 bits)
1596|-
1597|style="background-color: #ffcccc;" colspan="3"|64 bits total
1598|}
1599
1600all events will be the same size (64 bits).
1601
1602=== NexusLite Plug-in ===
1603
1604Create a '''New''', '''Project...''', '''Plug-in Project''', set the title to '''com.example.nexuslite''', click '''Next >''' then click on '''Finish'''.
1605
1606Now the structure for the Nexus trace Plug-in is set up.
1607
1608Add a dependency to TMF core and UI by opening the '''MANIFEST.MF''' in '''META-INF''', selecting the '''Dependencies''' tab and '''Add ...''' '''org.eclipse.linuxtools.tmf.core''' and '''org.eclipse.linuxtools.tmf.ui'''.
1609
1610[[Image:images/NTTAddDepend.png]]<br>
1611[[Image:images/NTTSelectProjects.png]]<br>
1612
1613Now the project can access TMF classes.
1614
1615===Trace Event===
1616
1617The '''TmfEvent''' class will work for this example. No code required.
1618
1619===Trace Reader===
1620
1621The trace reader will extend a '''TmfTrace''' class.
1622
1623It will need to implement:
1624
1625* validate (is the trace format valid?)
1626
1627* initTrace (called as the trace is opened
1628
1629* seekEvent (go to a position in the trace and create a context)
1630
1631* getNext (implemented in the base class)
1632
1633* parseEvent (read the next element in the trace)
1634
1635Here is an example implementation of the Nexus Trace file
1636
1637<pre>/*******************************************************************************
1638 * Copyright (c) 2013 Ericsson
1639 *
1640 * All rights reserved. This program and the accompanying materials are
1641 * made available under the terms of the Eclipse Public License v1.0 which
1642 * accompanies this distribution, and is available at
1643 * http://www.eclipse.org/legal/epl-v10.html
1644 *
1645 * Contributors:
1646 * Matthew Khouzam - Initial API and implementation
1647 *******************************************************************************/
1648
1649package com.example.nexuslite;
1650
1651import java.io.BufferedReader;
1652import java.io.File;
1653import java.io.FileInputStream;
1654import java.io.FileNotFoundException;
1655import java.io.FileReader;
1656import java.io.IOException;
1657import java.nio.MappedByteBuffer;
1658import java.nio.channels.FileChannel;
1659import java.nio.channels.FileChannel.MapMode;
1660
1661import org.eclipse.core.resources.IProject;
1662import org.eclipse.core.resources.IResource;
1663import org.eclipse.core.runtime.IStatus;
1664import org.eclipse.core.runtime.Status;
1665import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
1666import org.eclipse.linuxtools.tmf.core.event.ITmfEventField;
1667import org.eclipse.linuxtools.tmf.core.event.TmfEvent;
1668import org.eclipse.linuxtools.tmf.core.event.TmfEventField;
1669import org.eclipse.linuxtools.tmf.core.event.TmfEventType;
1670import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
1671import org.eclipse.linuxtools.tmf.core.timestamp.ITmfTimestamp;
1672import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
1673import org.eclipse.linuxtools.tmf.core.trace.ITmfContext;
1674import org.eclipse.linuxtools.tmf.core.trace.ITmfEventParser;
1675import org.eclipse.linuxtools.tmf.core.trace.ITmfLocation;
1676import org.eclipse.linuxtools.tmf.core.trace.TmfContext;
1677import org.eclipse.linuxtools.tmf.core.trace.TmfLongLocation;
1678import org.eclipse.linuxtools.tmf.core.trace.TmfTrace;
1679
1680/**
1681 * Nexus trace type
1682 *
1683 * @author Matthew Khouzam
1684 */
1685public class NexusTrace extends TmfTrace implements ITmfEventParser {
1686
1687 private static final int CHUNK_SIZE = 65536; // seems fast on MY system
1688 private static final int EVENT_SIZE = 8; // according to spec
1689
1690 private TmfLongLocation fCurrentLocation;
1691 private static final TmfLongLocation NULLLOCATION = new TmfLongLocation(
1692 (Long) null);
1693 private static final TmfContext NULLCONTEXT = new TmfContext(NULLLOCATION,
1694 -1L);
1695
1696 private long fSize;
1697 private long fOffset;
1698 private File fFile;
1699 private String[] fEventTypes;
1700 private FileChannel fFileChannel;
1701 private MappedByteBuffer fMappedByteBuffer;
1702
1703 @Override
1704 public IStatus validate(@SuppressWarnings("unused") IProject project,
1705 String path) {
1706 File f = new File(path);
1707 if (!f.exists()) {
1708 return new Status(IStatus.ERROR, Activator.PLUGIN_ID,
1709 "File does not exist"); //$NON-NLS-1$
1710 }
1711 if (!f.isFile()) {
1712 return new Status(IStatus.ERROR, Activator.PLUGIN_ID, path
1713 + " is not a file"); //$NON-NLS-1$
1714 }
1715 String header = readHeader(f);
1716 if (header.split(",", 64).length == 64) { //$NON-NLS-1$
1717 return Status.OK_STATUS;
1718 }
1719 return new Status(IStatus.ERROR, Activator.PLUGIN_ID,
1720 "File does not start as a CSV"); //$NON-NLS-1$
1721 }
1722
1723 @Override
1724 public ITmfLocation getCurrentLocation() {
1725 return fCurrentLocation;
1726 }
1727
1728 @Override
1729 public void initTrace(IResource resource, String path,
1730 Class<? extends ITmfEvent> type) throws TmfTraceException {
1731 super.initTrace(resource, path, type);
1732 fFile = new File(path);
1733 fSize = fFile.length();
1734 if (fSize == 0) {
1735 throw new TmfTraceException("file is empty"); //$NON-NLS-1$
1736 }
1737 String header = readHeader(fFile);
1738 if (header == null) {
1739 throw new TmfTraceException("File does not start as a CSV"); //$NON-NLS-1$
1740 }
1741 fEventTypes = header.split(",", 64); // 64 values of types according to //$NON-NLS-1$
1742 // the 'spec'
1743 if (fEventTypes.length != 64) {
1744 throw new TmfTraceException(
1745 "Trace header does not contain 64 event names"); //$NON-NLS-1$
1746 }
1747 if (getNbEvents() < 1) {
1748 throw new TmfTraceException("Trace does not have any events"); //$NON-NLS-1$
1749 }
1750 try {
1751 fFileChannel = new FileInputStream(fFile).getChannel();
1752 seek(0);
1753 } catch (FileNotFoundException e) {
1754 throw new TmfTraceException(e.getMessage());
1755 } catch (IOException e) {
1756 throw new TmfTraceException(e.getMessage());
1757 }
1758 }
1759
1760 /**
1761 * @return
1762 */
1763 private String readHeader(File file) {
1764 String header = new String();
1765 BufferedReader br;
1766 try {
1767 br = new BufferedReader(new FileReader(file));
1768 header = br.readLine();
1769 br.close();
1770 } catch (IOException e) {
1771 return null;
1772 }
1773 fOffset = header.length() + 1;
1774 setNbEvents((fSize - fOffset) / EVENT_SIZE);
1775 return header;
1776 }
1777
1778 @Override
1779 public double getLocationRatio(ITmfLocation location) {
1780 return ((TmfLongLocation) location).getLocationInfo().doubleValue()
1781 / getNbEvents();
1782 }
1783
1784 @Override
1785 public ITmfContext seekEvent(ITmfLocation location) {
1786 TmfLongLocation nl = (TmfLongLocation) location;
1787 if (location == null) {
1788 nl = new TmfLongLocation(0L);
1789 }
1790 try {
1791 seek(nl.getLocationInfo());
1792 } catch (IOException e) {
1793 return NULLCONTEXT;
1794 }
1795 return new TmfContext(nl, nl.getLocationInfo());
1796 }
1797
1798 @Override
1799 public ITmfContext seekEvent(double ratio) {
1800 long rank = (long) (ratio * getNbEvents());
1801 try {
1802 seek(rank);
1803 } catch (IOException e) {
1804 return NULLCONTEXT;
1805 }
1806 return new TmfContext(new TmfLongLocation(rank), rank);
1807 }
1808
1809 private void seek(long rank) throws IOException {
1810 final long position = fOffset + (rank * EVENT_SIZE);
1811 int size = Math.min((int) (fFileChannel.size() - position), CHUNK_SIZE);
1812 fMappedByteBuffer = fFileChannel.map(MapMode.READ_ONLY, position, size);
1813 }
1814
1815 @Override
1816 public ITmfEvent parseEvent(ITmfContext context) {
1817 if ((context == null) || (context.getRank() == -1)) {
1818 return null;
1819 }
1820 TmfEvent event = null;
1821 long ts = -1;
1822 int type = -1;
1823 int payload = -1;
1824 long pos = context.getRank();
1825 if (pos < getNbEvents()) {
1826 try {
1827 // if we are approaching the limit size, move to a new window
1828 if ((fMappedByteBuffer.position() + EVENT_SIZE) > fMappedByteBuffer
1829 .limit()) {
1830 seek(context.getRank());
1831 }
1832 /*
1833 * the trace format, is:
1834 *
1835 * - 32 bits for the time,
1836 * - 6 for the event type,
1837 * - 26 for the data.
1838 *
1839 * all the 0x00 stuff are masks.
1840 */
1841
1842 /*
1843 * it may be interesting to assume if the ts goes back in time,
1844 * it actually is rolling over we would need to keep the
1845 * previous timestamp for that, keep the high bits and increment
1846 * them if the next int ts read is lesser than the previous one
1847 */
1848
1849 ts = 0x00000000ffffffffL & fMappedByteBuffer.getInt();
1850
1851 long data = 0x00000000ffffffffL & fMappedByteBuffer.getInt();
1852 type = (int) (data >> 26) & (0x03f); // first 6 bits
1853 payload = (int) (data & 0x003FFFFFFL); // last 26 bits
1854 // the time is in microseconds.
1855 TmfTimestamp timestamp = new TmfTimestamp(ts, ITmfTimestamp.MICROSECOND_SCALE);
1856 final String title = fEventTypes[type];
1857 // put the value in a field
1858 final TmfEventField tmfEventField = new TmfEventField(
1859 "value", payload, null); //$NON-NLS-1$
1860 // the field must be in an array
1861 final TmfEventField[] fields = new TmfEventField[1];
1862 fields[0] = tmfEventField;
1863 final TmfEventField content = new TmfEventField(
1864 ITmfEventField.ROOT_FIELD_ID, null, fields);
1865 // set the current location
1866
1867 fCurrentLocation = new TmfLongLocation(pos);
1868 // create the event
1869 event = new TmfEvent(this, pos, timestamp, null,
1870 new TmfEventType(title, title, null), content, null);
1871 } catch (IOException e) {
1872 fCurrentLocation = new TmfLongLocation(-1L);
1873 }
1874 }
1875 return event;
1876 }
1877}
1878</pre>
1879
1880In this example the '''validate''' function checks if the file exists and is not a directory.
1881
1882The '''initTrace''' function will read the event names, and find where the data starts. After this, the number of events is known, and since each event is 8 bytes long according to the specs, the seek is then trivial.
1883
1884The '''seek''' here will just reset the reader to the right location.
1885
1886The '''parseEvent''' method needs to parse and return the current event and store the current location.
1887
1888The '''getNext''' method (in base class) will read the next event and update the context. It calls the '''parseEvent''' method to read the event and update the location. It does not need to be overridden and in this example it is not. The sequence of actions necessary are parse the next event from the trace, create an '''ITmfEvent''' with that data, update the current location, call '''updateAttributes''', update the context then return the event.
1889
1890===Trace Context===
1891
1892The trace context will be a '''TmfContext'''
1893
1894===Trace Location===
1895
1896The trace location will be a long, representing the rank in the file. The '''TmfLongLocation''' will be the used, once again, no code is required.
1897
1898===(Optional but recommended) The ''org.eclipse.linuxtools.tmf.ui.tracetype'' plug-in extension point===
1899
1900One can implement the ''tracetype'' extension in their own plug-in. In this example, the ''com.example.nexuslite'' plug-in will be modified.
1901
1902The '''plugin.xml''' file in the ui plug-in needs to be updated if one wants users to access the given event type. It can be updated in the Eclipse plug-in editor.
1903
1904# In Extensions tab, add the '''org.eclipse.linuxtools.tmf.ui.tracetype''' extension point.
1905[[Image:images/NTTExtension.png]]<br>
1906[[Image:images/NTTTraceType.png]]<br>
1907[[Image:images/NTTExtensionPoint.png]]<br>
1908
1909# Add in the '''org.eclipse.linuxtools.tmf.ui.tracetype''' extension a new type. To do that, '''right click''' on the extension then in the context menu, go to '''New >''', '''type'''.
1910
1911[[Image:images/NTTAddType.png]]<br>
1912
1913The '''id''' is the unique identifier used to refer to the trace.
1914
1915The '''name''' is the field that shall be displayed when a trace type is selected.
1916
1917The '''trace type''' is the canonical path refering to the class of the trace.
1918
1919The '''event type''' is the canonical path refering to the class of the events of a given trace.
1920
1921The '''category''' (optional) is the container in which this trace type will be stored.
1922
1923The '''icon''' (optional) is the image to associate with that trace type.
1924
1925In the end, the extension menu should look like this.
1926
1927[[Image:images/NTTPluginxmlComplete.png]]<br>
1928
1929==Best Practices==
1930
1931* Do not load the whole trace in RAM, it will limit the size of the trace that can be read.
1932* Reuse as much code as possible, it makes the trace format much easier to maintain.
1933* Use Eclipse's editor instead of editing the xml directly.
1934* Do not forget Java supports only signed data types, there may be special care needed to handle unsigned data.
1935* Keep all the code in the same plug-in as the ''tracetype'' if it makes sense from a design point of view. It will make integration easier.
1936
1937== Download the Code ==
1938
1939The plug-in is available [http://wiki.eclipse.org/images/3/34/Com.example.nexuslite.zip here] with a trace generator and a quick test case.
1940
1941
067490ab
AM
1942=CTF Parser=
1943
5f7ef209 1944== CTF Format ==
2819a797 1945CTF is a format used to store traces. It is self defining, binary and made to be easy to write to.
067490ab
AM
1946Before going further, the full specification of the CTF file format can be found at http://www.efficios.com/ .
1947
5f7ef209 1948For the purpose of the reader some basic description will be given. A CTF trace typically is made of several files all in the same folder.
067490ab 1949
5f7ef209 1950These files can be split into two types :
067490ab
AM
1951* Metadata
1952* Event streams
5f7ef209 1953
067490ab 1954=== Metadata ===
5f7ef209 1955The metadata is either raw text or packetized text. It is tsdl encoded. it contains a description of the type of data in the event streams. It can grow over time if new events are added to a trace but it will never overwrite what is already there.
067490ab
AM
1956
1957=== Event Streams ===
5f7ef209 1958The event streams are a file per stream per cpu. These streams are binary and packet based. The streams store events and event information (ie lost events) The event data is stored in headers and field payloads.
067490ab
AM
1959
1960So if you have two streams (channels) "channel1" and "channel2" and 4 cores, you will have the following files in your trace directory: "channel1_0" , "channel1_1" , "channel1_2" , "channel1_3" , "channel2_0" , "channel2_1" , "channel2_2" & "channel2_3"
1961
1962== Reading a trace ==
1963In order to read a CTF trace, two steps must be done.
1964* The metadata must be read to know how to read the events.
1965* the events must be read.
1966
5f7ef209 1967The metadata is a written in a subset of the C language called TSDL. To read it, first it is depacketized (if it is not in plain text) then the raw text is parsed by an antlr grammer. The parsing is done in two phases. There is a lexer (CTFLexer.g) which separated the metatdata text into tokens. The tokens are then pattern matched using the parser (CTFParser.g) to form an AST. This AST is walked through using "IOStructGen.java" to populate streams and traces in trace parent object.
067490ab 1968
5f7ef209
MK
1969When the metadata is loaded and read, the trace object will be populated with 3 items:
1970* the event definitions available per stream: a definition is a description of the datatype.
1971* the event declarations available per stream: this will save declaration creation on a per event basis. They will all be created in advance, just not populated.
1972* the beginning of a packet index.
067490ab 1973
5f7ef209 1974Now all the trace readers for the event streams have everything they need to read a trace. They will each point to one file, and read the file from packet to packet. Everytime the trace reader changes packet, the index is updated with the new packet's information. The readers are in a priority queue and sorted by timestamp. This ensures that the events are read in a sequential order. They are also sorted by file name so that in the eventuality that two events occur at the same time, they stay in the same order.
067490ab
AM
1975
1976== Seeking in a trace ==
5f7ef209 1977The reason for maintaining an index is to speed up seeks. In the case that a user wishes to seek to a certain timestamp, they just have to find the index entry that contains the timestamp, and go there to iterate in that packet until the proper event is found. this will reduce the searches time by an order of 8000 for a 256k paket size (kernel default).
067490ab
AM
1978
1979== Interfacing to TMF ==
5f7ef209 1980The trace can be read easily now but the data is still awkward to extract.
067490ab
AM
1981
1982=== CtfLocation ===
5f7ef209 1983A location in a given trace, it is currently the timestamp of a trace and the index of the event. The index shows for a given timestamp if it is the first second or nth element.
067490ab
AM
1984
1985=== CtfTmfTrace ===
1986The CtfTmfTrace is a wrapper for the standard CTF trace that allows it to perform the following actions:
5f7ef209
MK
1987* '''initTrace()''' create a trace
1988* '''validateTrace()''' is the trace a CTF trace?
1989* '''getLocationRatio()''' how far in the trace is my location?
1990* '''seekEvent()''' sets the cursor to a certain point in a trace.
1991* '''readNextEvent()''' reads the next event and then advances the cursor
1992* '''getTraceProperties()''' gets the 'env' structures of the metadata
067490ab
AM
1993
1994=== CtfIterator ===
1995The CtfIterator is a wrapper to the CTF file reader. It behaves like an iterator on a trace. However, it contains a file pointer and thus cannot be duplicated too often or the system will run out of file handles. To alleviate the situation, a pool of iterators is created at the very beginning and stored in the CtfTmfTrace. They can be retried by calling the GetIterator() method.
1996
5f7ef209
MK
1997=== CtfIteratorManager ===
1998Since each CtfIterator will have a file reader, the OS will run out of handles if too many iterators are spawned. The solution is to use the iterator manager. This will allow the user to get an iterator. If there is a context at the requested position, the manager will return that one, if not, a context will be selected at random and set to the correct location. Using random replacement minimizes contention as it will settle quickly at a new balance point.
1999
2000=== CtfTmfContext ===
2001The CtfTmfContext implements the ITmfContext type. It is the CTF equivalent of TmfContext. It has a CtfLocation and points to an iterator in the CtfTmfTrace iterator pool as well as the parent trace. it is made to be cloned easily and not affect system resources much. Contexts behave much like C file pointers (FILE*) but they can be copied until one runs out of RAM.
067490ab
AM
2002
2003=== CtfTmfTimestamp ===
2004The CtfTmfTimestamp take a CTF time (normally a long int) and outputs the time formats it as a TmfTimestamp, allowing it to be compared to other timestamps. The time is stored with the UTC offset already applied. It also features a simple toString() function that allows it to output the time in more Human readable ways: "yyyy/mm/dd/hh:mm:ss.nnnnnnnnn ns" for example. An additional feature is the getDelta() function that allows two timestamps to be substracted, showing the time difference between A and B.
2005
2006=== CtfTmfEvent ===
5f7ef209 2007The CtfTmfEvent is an ITmfEvent that is used to wrap event declarations and event definitions from the CTF side into easier to read and parse chunks of information. It is a final class with final fields made to be newed very often without incurring performance costs. Most of the information is already available. It should be noted that one type of event can appear called "lost event" these are synthetic events that do not exist in the trace. They will not appear in other trace readers such as babeltrace.
067490ab
AM
2008
2009=== Other ===
5f7ef209 2010There are other helper files that format given events for views, they are simpler and the architecture does not depend on them.
067490ab
AM
2011
2012=== Limitations ===
2013For the moment live trace reading is not supported, there are no sources of traces to test on.
32897d73
AM
2014
2015
2016= Generic State System =
2017
2018== Introduction ==
2019
2020The Generic State System is a utility available in TMF to track different states
2021over the duration of a trace. It works by first sending some or all events of
2022the trace into a state provider, which defines the state changes for a given
2023trace type. Once built, views and analysis modules can then query the resulting
2024database of states (called "state history") to get information.
2025
2026For example, let's suppose we have the following sequence of events in a kernel
2027trace:
2028
2029 10 s, sys_open, fd = 5, file = /home/user/myfile
2030 ...
2031 15 s, sys_read, fd = 5, size=32
2032 ...
2033 20 s, sys_close, fd = 5
2034
2035Now let's say we want to implement an analysis module which will track the
2036amount of bytes read and written to eachfile. Here, of course the sys_read is
2037interesting. However, by just looking at that event, we have no information on
2038which file is being read, only its fd (5) is known. To get the match
2039fd5 = /home/user/myfile, we have to go back to the sys_open event which happens
20405 seconds earlier.
2041
2042But since we don't know exactly where this sys_open event is, we will have to go
2043back to the very start of the trace, and look through events one by one! This is
2044obviously not efficient, and will not scale well if we want to analyze many
2045similar patterns, or for very large traces.
2046
2047A solution in this case would be to use the state system to keep track of the
2048amount of bytes read/written to every *filename* (instead of every file
2049descriptor, like we get from the events). Then the module could ask the state
2050system "what is the amount of bytes read for file "/home/user/myfile" at time
205116 s", and it would return the answer "32" (assuming there is no other read
2052than the one shown).
2053
2054== High-level components ==
2055
2056The State System infrastructure is composed of 3 parts:
2057* The state provider
2058* The central state system
2059* The storage backend
2060
2061The state provider is the customizable part. This is where the mapping from
2062trace events to state changes is done. This is what you want to implement for
2063your specific trace type and analysis type. It's represented by the
2064ITmfStateProvider interface (with a threaded implementation in
2065AbstractTmfStateProvider, which you can extend).
2066
2067The core of the state system is exposed through the ITmfStateSystem and
2068ITmfStateSystemBuilder interfaces. The former allows only read-only access and
2069is typically used for views doing queries. The latter also allows writing to the
2070state history, and is typically used by the state provider.
2071
2072Finally, each state system has its own separate backend. This determines how the
2073intervals, or the "state history", are saved (in RAM, on disk, etc.) You can
2074select the type of backend at construction time in the TmfStateSystemFactory.
2075
2076== Definitions ==
2077
2078Before we dig into how to use the state system, we should go over some useful
2079definitions:
2080
2081=== Attribute ===
2082
2083An attribute is the smallest element of the model that can be in any particular
2084state. When we refer to the "full state", in fact it means we are interested in
2085the state of every single attribute of the model.
2086
2087=== Attribute Tree ===
2088
2089Attributes in the model can be placed in a tree-like structure, a bit like files
2090and directories in a file system. However, note that an attribute can always
2091have both a value and sub-attributes, so they are like files and directories at
2092the same time. We are then able to refer to every single attribute with its
2093path in the tree.
2094
2095For example, in the attribute tree for LTTng kernel traces, we use the following
2096attributes, among others:
2097
2098<pre>
2099|- Processes
2100| |- 1000
2101| | |- PPID
2102| | |- Exec_name
2103| |- 1001
2104| | |- PPID
2105| | |- Exec_name
2106| ...
2107|- CPUs
2108 |- 0
2109 | |- Status
2110 | |- Current_pid
2111 ...
2112</pre>
2113
2114In this model, the attribute "Processes/1000/PPID" refers to the PPID of process
2115with PID 1000. The attribute "CPUs/0/Status" represents the status (running,
2116idle, etc.) of CPU 0. "Processes/1000/PPID" and "Processes/1001/PPID" are two
2117different attribute, even though their base name is the same: the whole path is
2118the unique identifier.
2119
2120The value of each attribute can change over the duration of the trace,
2121independently of the other ones, and independently of its position in the tree.
2122
2123The tree-like organization is optional, all attributes could be at the same
2124level. But it's possible to put them in a tree, and it helps make things
2125clearer.
2126
2127=== Quark ===
2128
2129In addition to a given path, each attribute also has a unique integer
2130identifier, called the "quark". To continue with the file system analogy, this
2131is like the inode number. When a new attribute is created, a new unique quark
2132will be assigned automatically. They are assigned incrementally, so they will
2133normally be equal to their order of creation, starting at 0.
2134
2135Methods are offered to get the quark of an attribute from its path. The API
2136methods for inserting state changes and doing queries normally use quarks
2137instead of paths. This is to encourage users to cache the quarks and re-use
2138them, which avoids re-walking the attribute tree over and over, which avoids
2139unneeded hashing of strings.
2140
2141=== State value ===
2142
2143The path and quark of an attribute will remain constant for the whole duration
2144of the trace. However, the value carried by the attribute will change. The value
2145of a specific attribute at a specific time is called the state value.
2146
2147In the TMF implementation, state values can be integers, longs, or strings.
2148There is also a "null value" type, which is used to indicate that no particular
2149value is active for this attribute at this time, but without resorting to a
2150'null' reference.
2151
2152Any other type of value could be used, as long as the backend knows how to store
2153it.
2154
2155Note that the TMF implementation also forces every attribute to always carry the
2156same type of state value. This is to make it simpler for views, so they can
2157expect that an attribute will always use a given type, without having to check
2158every single time. Null values are an exception, they are always allowed for all
2159attributes, since they can safely be "unboxed" into all types.
2160
2161=== State change ===
2162
2163A state change is the element that is inserted in the state system. It consists
2164of:
2165* a timestamp (the time at which the state change occurs)
2166* an attribute (the attribute whose value will change)
2167* a state value (the new value that the attribute will carry)
2168
2169It's not an object per se in the TMF implementation (it's represented by a
2170function call in the state provider). Typically, the state provider will insert
2171zero, one or more state changes for every trace event, depending on its event
2172type, payload, etc.
2173
2174Note, we use "timestamp" here, but it's in fact a generic term that could be
2175referred to as "index". For example, if a given trace type has no notion of
2176timestamp, the event rank could be used.
2177
2178In the TMF implementation, the timestamp is a long (64-bit integer).
2179
2180=== State interval ===
2181
2182State changes are inserted into the state system, but state intervals are the
2183objects that come out on the other side. Those are stocked in the storage
2184backend. A state interval represents a "state" of an attribute we want to track.
2185When doing queries on the state system, intervals are what is returned. The
2186components of a state interval are:
2187* Start time
2188* End time
2189* State value
2190* Quark
2191
2192The start and end times represent the time range of the state. The state value
2193is the same as the state value in the state change that started this interval.
2194The interval also keeps a reference to its quark, although you normally know
2195your quark in advance when you do queries.
2196
2197=== State history ===
2198
2199The state history is the name of the container for all the intervals created by
2200the state system. The exact implementation (how the intervals are stored) is
2201determined by the storage backend that is used.
2202
2203Some backends will use a state history that is peristent on disk, others do not.
2204When loading a trace, if a history file is available and the backend supports
2205it, it will be loaded right away, skipping the need to go through another
2206construction phase.
2207
2208=== Construction phase ===
2209
2210Before we can query a state system, we need to build the state history first. To
2211do so, trace events are sent one-by-one through the state provider, which in
2212turn sends state changes to the central component, which then creates intervals
2213and stores them in the backend. This is called the construction phase.
2214
2215Note that the state system needs to receive its events into chronological order.
2216This phase will end once the end of the trace is reached.
2217
2218Also note that it is possible to query the state system while it is being build.
2219Any timestamp between the start of the trace and the current end time of the
2220state system (available with ITmfStateSystem#getCurrentEndTime()) is a valid
2221timestamp that can be queried.
2222
2223=== Queries ===
2224
2225As mentioned previously, when doing queries on the state system, the returned
2226objects will be state intervals. In most cases it's the state *value* we are
2227interested in, but since the backend has to instantiate the interval object
2228anyway, there is no additional cost to return the interval instead. This way we
2229also get the start and end times of the state "for free".
2230
2231There are two types of queries that can be done on the state system:
2232
2233==== Full queries ====
2234
2235A full query means that we want to retrieve the whole state of the model for one
2236given timestamp. As we remember, this means "the state of every single attribute
2237in the model". As parameter we only need to pass the timestamp (see the API
2238methods below). The return value will be an array of intervals, where the offset
2239in the array represents the quark of each attribute.
2240
2241==== Single queries ====
2242
2243In other cases, we might only be interested in the state of one particular
2244attribute at one given timestamp. For these cases it's better to use a
2245single query. For a single query. we need to pass both a timestamp and a
2246quark in parameter. The return value will be a single interval, representing
2247the state that this particular attribute was at that time.
2248
2249Single queries are typically faster than full queries (but once again, this
2250depends on the backend that is used), but not by much. Even if you only want the
2251state of say 10 attributes out of 200, it could be faster to use a full query
2252and only read the ones you need. Single queries should be used for cases where
2253you only want one attribute per timestamp (for example, if you follow the state
2254of the same attribute over a time range).
2255
2256
2257== Relevant interfaces/classes ==
2258
2259This section will describe the public interface and classes that can be used if
2260you want to use the state system.
2261
2262=== Main classes in org.eclipse.linuxtools.tmf.core.statesystem ===
2263
2264==== ITmfStateProvider / AbstractTmfStateProvider ====
2265
2266ITmfStateProvider is the interface you have to implement to define your state
2267provider. This is where most of the work has to be done to use a state system
2268for a custom trace type or analysis type.
2269
2270For first-time users, it's recommended to extend AbstractTmfStateProvider
2271instead. This class takes care of all the initialization mumbo-jumbo, and also
2272runs the event handler in a separate thread. You will only need to implement
2273eventHandle, which is the call-back that will be called for every event in the
2274trace.
2275
2276For an example, you can look at StatsStateProvider in the TMF tree, or at the
2277small example below.
2278
2279==== TmfStateSystemFactory ====
2280
2281Once you have defined your state provider, you need to tell your trace type to
2282build a state system with this provider during its initialization. This consists
2283of overriding TmfTrace#buildStateSystems() and in there of calling the method in
2284TmfStateSystemFactory that corresponds to the storage backend you want to use
2285(see the section [[#Comparison of state system backends]]).
2286
2287You will have to pass in parameter the state provider you want to use, which you
2288should have defined already. Each backend can also ask for more configuration
2289information.
2290
2291You must then call registerStateSystem(id, statesystem) to make your state
2292system visible to the trace objects and the views. The ID can be any string of
2293your choosing. To access this particular state system, the views or modules will
2294need to use this ID.
2295
2296Also, don't forget to call super.buildStateSystems() in your implementation,
2297unless you know for sure you want to skip the state providers built by the
2298super-classes.
2299
2300You can look at how LttngKernelTrace does it for an example. It could also be
2301possible to build a state system only under certain conditions (like only if the
2302trace contains certain event types).
2303
2304
2305==== ITmfStateSystem ====
2306
2307ITmfStateSystem is the main interface through which views or analysis modules
2308will access the state system. It offers a read-only view of the state system,
2309which means that no states can be inserted, and no attributes can be created.
2310Calling TmfTrace#getStateSystems().get(id) will return you a ITmfStateSystem
2311view of the requested state system. The main methods of interest are:
2312
2313===== getQuarkAbsolute()/getQuarkRelative() =====
2314
2315Those are the basic quark-getting methods. The goal of the state system is to
2316return the state values of given attributes at given timestamps. As we've seen
2317earlier, attributes can be described with a file-system-like path. The goal of
2318these methods is to convert from the path representation of the attribute to its
2319quark.
2320
2321Since quarks are created on-the-fly, there is no guarantee that the same
2322attributes will have the same quark for two traces of the same type. The views
2323should always query their quarks when dealing with a new trace or a new state
2324provider. Beyond that however, quarks should be cached and reused as much as
2325possible, to avoid potentially costly string re-hashing.
2326
2327getQuarkAbsolute() takes a variable amount of Strings in parameter, which
2328represent the full path to the attribute. Some of them can be constants, some
2329can come programatically, often from the event's fields.
2330
2331getQuarkRelative() is to be used when you already know the quark of a certain
2332attribute, and want to access on of its sub-attributes. Its first parameter is
2333the origin quark, followed by a String varagrs which represent the relative path
2334to the final attribute.
2335
2336These two methods will throw an AttributeNotFoundException if trying to access
2337an attribute that does not exist in the model.
2338
2339These methods also imply that the view has the knowledge of how the attribute
2340tree is organized. This should be a reasonable hypothesis, since the same
2341analysis plugin will normally ship both the state provider and the view, and
2342they will have been written by the same person. In other cases, it's possible to
2343use getSubAttributes() to explore the organization of the attribute tree first.
2344
2345===== waitUntilBuilt() =====
2346
2347This is a simple method used to block the caller until the construction phase of
2348this state system is done. If the view prefers to wait until all information is
2349available before starting to do queries (to get all known attributes right away,
2350for example), this is the guy to call.
2351
2352===== queryFullState() =====
2353
2354This is the method to do full queries. As mentioned earlier, you only need to
2355pass a target timestamp in parameter. It will return a List of state intervals,
2356in which the offset corresponds to the attribute quark. This will represent the
2357complete state of the model at the requested time.
2358
2359===== querySingleState() =====
2360
2361The method to do single queries. You pass in parameter both a timestamp and an
2362attribute quark. This will return the single state matching this
2363timestamp/attribute pair.
2364
2365Other methods are available, you are encouraged to read their Javadoc and see if
2366they can be potentially useful.
2367
2368==== ITmfStateSystemBuilder ====
2369
2370ITmfStateSystemBuilder is the read-write interface to the state system. It
2371extends ITmfStateSystem itself, so all its methods are available. It then adds
2372methods that can be used to write to the state system, either by creating new
2373attributes of inserting state changes.
2374
2375It is normally reserved for the state provider and should not be visible to
2376external components. However it will be available in AbstractTmfStateProvider,
2377in the field 'ss'. That way you can call ss.modifyAttribute() etc. in your state
2378provider to write to the state.
2379
2380The main methods of interest are:
2381
2382===== getQuark*AndAdd() =====
2383
2384getQuarkAbsoluteAndAdd() and getQuarkRelativeAndAdd() work exactly like their
2385non-AndAdd counterparts in ITmfStateSystem. The difference is that the -AndAdd
2386versions will not throw any exception: if the requested attribute path does not
2387exist in the system, it will be created, and its newly-assigned quark will be
2388returned.
2389
2390When in a state provider, the -AndAdd version should normally be used (unless
2391you know for sure the attribute already exist and don't want to create it
2392otherwise). This means that there is no need to define the whole attribute tree
2393in advance, the attributes will be created on-demand.
2394
2395===== modifyAttribute() =====
2396
2397This is the main state-change-insertion method. As was explained before, a state
2398change is defined by a timestamp, an attribute and a state value. Those three
2399elements need to be passed to modifyAttribute as parameters.
2400
2401Other state change insertion methods are available (increment-, push-, pop- and
2402removeAttribute()), but those are simply convenience wrappers around
2403modifyAttribute(). Check their Javadoc for more information.
2404
2405===== closeHistory() =====
2406
2407When the construction phase is done, do not forget to call closeHistory() to
2408tell the backend that no more intervals will be received. Depending on the
2409backend type, it might have to save files, close descriptors, etc. This ensures
2410that a persitent file can then be re-used when the trace is opened again.
2411
2412If you use the AbstractTmfStateProvider, it will call closeHistory()
2413automatically when it reaches the end of the trace.
2414
2415=== Other relevant interfaces ===
2416
2417==== o.e.l.tmf.core.statevalue.ITmfStateValue ====
2418
2419This is the interface used to represent state values. Those are used when
2420inserting state changes in the provider, and is also part of the state intervals
2421obtained when doing queries.
2422
2423The abstract TmfStateValue class contains the factory methods to create new
2424state values of either int, long or string types. To retrieve the real object
2425inside the state value, one can use the .unbox* methods.
2426
2427Note: Do not instantiate null values manually, use TmfStateValue.nullValue()
2428
2429==== o.e.l.tmf.core.interval.ITmfStateInterval ====
2430
2431This is the interface to represent the state intervals, which are stored in the
2432state history backend, and are returned when doing state system queries. A very
2433simple implementation is available in TmfStateInterval. Its methods should be
2434self-descriptive.
2435
2436=== Exceptions ===
2437
2438The following exceptions, found in o.e.l.tmf.core.exceptions, are related to
2439state system activities.
2440
2441==== AttributeNotFoundException ====
2442
2443This is thrown by getQuarkRelative() and getQuarkAbsolute() (but not byt the
2444-AndAdd versions!) when passing an attribute path that is not present in the
2445state system. This is to ensure that no new attribute is created when using
2446these versions of the methods.
2447
2448Views can expect some attributes to be present, but they should handle these
2449exceptions for when the attributes end up not being in the state system (perhaps
2450this particular trace didn't have a certain type of events, etc.)
2451
2452==== StateValueTypeException ====
2453
2454This exception will be thrown when trying to unbox a state value into a type
2455different than its own. You should always check with ITmfStateValue#getType()
2456beforehand if you are not sure about the type of a given state value.
2457
2458==== TimeRangeException ====
2459
2460This exception is thrown when trying to do a query on the state system for a
2461timestamp that is outside of its range. To be safe, you should check with
2462ITmfStateSystem#getStartTime() and #getCurrentEndTime() for the current valid
2463range of the state system. This is especially important when doing queries on
2464a state system that is currently being built.
2465
2466==== StateSystemDisposedException ====
2467
2468This exception is thrown when trying to access a state system that has been
2469disposed, with its dispose() method. This can potentially happen at shutdown,
2470since Eclipse is not always consistent with the order in which the components
2471are closed.
2472
2473
2474== Comparison of state system backends ==
2475
2476As we have seen in section [[#High-level components]], the state system needs
2477a storage backend to save the intervals. Different implementations are
2478available when building your state system from TmfStateSystemFactory.
2479
2480Do not confuse full/single queries with full/partial history! All backend types
2481should be able to handle any type of queries defined in the ITmfStateSystem API,
2482unless noted otherwise.
2483
2484=== Full history ===
2485
2486Available with TmfStateSystemFactory#newFullHistory(). The full history uses a
2487History Tree data structure, which is an optimized structure store state
2488intervals on disk. Once built, it can respond to queries in a ''log(n)'' manner.
2489
2490You need to specify a file at creation time, which will be the container for
2491the history tree. Once it's completely built, it will remain on disk (until you
2492delete the trace from the project). This way it can be reused from one session
2493to another, which makes subsequent loading time much faster.
2494
2495This the backend used by the LTTng kernel plugin. It offers good scalability and
2496performance, even at extreme sizes (it's been tested with traces of sizes up to
2497500 GB). Its main downside is the amount of disk space required: since every
2498single interval is written to disk, the size of the history file can quite
2499easily reach and even surpass the size of the trace itself.
2500
2501=== Null history ===
2502
2503Available with TmfStateSystemFactory#newNullHistory(). As its name implies the
2504null history is in fact an absence of state history. All its query methods will
2505return null (see the Javadoc in NullBackend).
2506
2507Obviously, no file is required, and almost no memory space is used.
2508
2509It's meant to be used in cases where you are not interested in past states, but
2510only in the "ongoing" one. It can also be useful for debugging and benchmarking.
2511
2512=== In-memory history ===
2513
2514Available with TmfStateSystemFactory#newInMemHistory(). This is a simple wrapper
2515using an ArrayList to store all state intervals in memory. The implementation
2516at the moment is quite simple, it will iterate through all entries when doing
2517queries to find the ones that match.
2518
2519The advantage of this method is that it's very quick to build and query, since
2520all the information resides in memory. However, you are limited to 2^31 entries
2521(roughly 2 billions), and depending on your state provider and trace type, that
2522can happen really fast!
2523
2524There are no safeguards, so if you bust the limit you will end up with
2525ArrayOutOfBoundsException's everywhere. If your trace or state history can be
2526arbitrarily big, it's probably safer to use a Full History instead.
2527
2528=== Partial history ===
2529
2530Available with TmfStateSystemFactory#newPartialHistory(). The partial history is
2531a more advanced form of the full history. Instead of writing all state intervals
2532to disk like with the full history, we only write a small fraction of them, and
2533go back to read the trace to recreate the states in-between.
2534
2535It has a big advantage over a full history in terms of disk space usage. It's
2536very possible to reduce the history tree file size by a factor of 1000, while
2537keeping query times within a factor of two. Its main downside comes from the
2538fact that you cannot do efficient single queries with it (they are implemented
2539by doing full queries underneath).
2540
2541This makes it a poor choice for views like the Control Flow view, where you do
2542a lot of range queries and single queries. However, it is a perfect fit for
2543cases like statistics, where you usually do full queries already, and you store
2544lots of small states which are very easy to "compress".
2545
2546However, it can't really be used until bug 409630 is fixed.
2547
2548== Code example ==
2549
2550Here is a small example of code that will use the state system. For this
2551example, let's assume we want to track the state of all the CPUs in a LTTng
2552kernel trace. To do so, we will watch for the "sched_switch" event in the state
2553provider, and will update an attribute indicating if the associated CPU should
2554be set to "running" or "idle".
2555
2556We will use an attribute tree that looks like this:
2557<pre>
2558CPUs
2559 |--0
2560 | |--Status
2561 |
2562 |--1
2563 | |--Status
2564 |
2565 | 2
2566 | |--Status
2567...
2568</pre>
2569
2570The second-level attributes will be named from the information available in the
2571trace events. Only the "Status" attributes will carry a state value (this means
2572we could have just used "1", "2", "3",... directly, but we'll do it in a tree
2573for the example's sake).
2574
2575Also, we will use integer state values to represent "running" or "idle", instead
2576of saving the strings that would get repeated every time. This will help in
2577reducing the size of the history file.
2578
2579First we will define a state provider in MyStateProvider. Then, assuming we
2580have already implemented a custom trace type extending CtfTmfTrace, we will add
2581a section to it to make it build a state system using the provider we defined
2582earlier. Finally, we will show some example code that can query the state
2583system, which would normally go in a view or analysis module.
2584
2585=== State Provider ===
2586
2587<pre>
2588import org.eclipse.linuxtools.tmf.core.ctfadaptor.CtfTmfEvent;
2589import org.eclipse.linuxtools.tmf.core.event.ITmfEvent;
2590import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
2591import org.eclipse.linuxtools.tmf.core.exceptions.StateValueTypeException;
2592import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
2593import org.eclipse.linuxtools.tmf.core.statesystem.AbstractTmfStateProvider;
2594import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
2595import org.eclipse.linuxtools.tmf.core.statevalue.TmfStateValue;
2596import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
2597
2598/**
2599 * Example state system provider.
2600 *
2601 * @author Alexandre Montplaisir
2602 */
2603public class MyStateProvider extends AbstractTmfStateProvider {
2604
2605 /** State value representing the idle state */
2606 public static ITmfStateValue IDLE = TmfStateValue.newValueInt(0);
2607
2608 /** State value representing the running state */
2609 public static ITmfStateValue RUNNING = TmfStateValue.newValueInt(1);
2610
2611 /**
2612 * Constructor
2613 *
2614 * @param trace
2615 * The trace to which this state provider is associated
2616 */
2617 public MyStateProvider(ITmfTrace trace) {
2618 super(trace, CtfTmfEvent.class, "Example"); //$NON-NLS-1$
2619 /*
2620 * The third parameter here is not important, it's only used to name a
2621 * thread internally.
2622 */
2623 }
2624
2625 @Override
2626 public int getVersion() {
2627 /*
2628 * If the version of an existing file doesn't match the version supplied
2629 * in the provider, a rebuild of the history will be forced.
2630 */
2631 return 1;
2632 }
2633
2634 @Override
2635 public MyStateProvider getNewInstance() {
2636 return new MyStateProvider(getTrace());
2637 }
2638
2639 @Override
2640 protected void eventHandle(ITmfEvent ev) {
2641 /*
2642 * AbstractStateChangeInput should have already checked for the correct
2643 * class type.
2644 */
2645 CtfTmfEvent event = (CtfTmfEvent) ev;
2646
2647 final long ts = event.getTimestamp().getValue();
2648 Integer nextTid = ((Long) event.getContent().getField("next_tid").getValue()).intValue();
2649
2650 try {
2651
2652 if (event.getEventName().equals("sched_switch")) {
2653 int quark = ss.getQuarkAbsoluteAndAdd("CPUs", String.valueOf(event.getCPU()), "Status");
2654 ITmfStateValue value;
2655 if (nextTid > 0) {
2656 value = RUNNING;
2657 } else {
2658 value = IDLE;
2659 }
2660 ss.modifyAttribute(ts, value, quark);
2661 }
2662
2663 } catch (TimeRangeException e) {
2664 /*
2665 * This should not happen, since the timestamp comes from a trace
2666 * event.
2667 */
2668 throw new IllegalStateException(e);
2669 } catch (AttributeNotFoundException e) {
2670 /*
2671 * This should not happen either, since we're only accessing a quark
2672 * we just created.
2673 */
2674 throw new IllegalStateException(e);
2675 } catch (StateValueTypeException e) {
2676 /*
2677 * This wouldn't happen here, but could potentially happen if we try
2678 * to insert mismatching state value types in the same attribute.
2679 */
2680 e.printStackTrace();
2681 }
2682
2683 }
2684
2685}
2686</pre>
2687
2688=== Trace type definition ===
2689
2690<pre>
2691import java.io.File;
2692
2693import org.eclipse.core.resources.IProject;
2694import org.eclipse.core.runtime.IStatus;
2695import org.eclipse.core.runtime.Status;
2696import org.eclipse.linuxtools.tmf.core.ctfadaptor.CtfTmfTrace;
2697import org.eclipse.linuxtools.tmf.core.exceptions.TmfTraceException;
2698import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateProvider;
2699import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
2700import org.eclipse.linuxtools.tmf.core.statesystem.TmfStateSystemFactory;
2701import org.eclipse.linuxtools.tmf.core.trace.TmfTraceManager;
2702
2703/**
2704 * Example of a custom trace type using a custom state provider.
2705 *
2706 * @author Alexandre Montplaisir
2707 */
2708public class MyTraceType extends CtfTmfTrace {
2709
2710 /** The file name of the history file */
2711 public final static String HISTORY_FILE_NAME = "mystatefile.ht";
2712
2713 /** ID of the state system we will build */
2714 public static final String STATE_ID = "org.eclipse.linuxtools.lttng2.example";
2715
2716 /**
2717 * Default constructor
2718 */
2719 public MyTraceType() {
2720 super();
2721 }
2722
2723 @Override
2724 public IStatus validate(final IProject project, final String path) {
2725 /*
2726 * Add additional validation code here, and return a IStatus.ERROR if
2727 * validation fails.
2728 */
2729 return Status.OK_STATUS;
2730 }
2731
2732 @Override
2733 protected void buildStateSystem() throws TmfTraceException {
2734 super.buildStateSystem();
2735
2736 /* Build the custom state system for this trace */
2737 String directory = TmfTraceManager.getSupplementaryFileDir(this);
2738 final File htFile = new File(directory + HISTORY_FILE_NAME);
2739 final ITmfStateProvider htInput = new MyStateProvider(this);
2740
2741 ITmfStateSystem ss = TmfStateSystemFactory.newFullHistory(htFile, htInput, false);
2742 fStateSystems.put(STATE_ID, ss);
2743 }
2744
2745}
2746</pre>
2747
2748=== Query code ===
2749
2750<pre>
2751import java.util.List;
2752
2753import org.eclipse.linuxtools.tmf.core.exceptions.AttributeNotFoundException;
2754import org.eclipse.linuxtools.tmf.core.exceptions.StateSystemDisposedException;
2755import org.eclipse.linuxtools.tmf.core.exceptions.TimeRangeException;
2756import org.eclipse.linuxtools.tmf.core.interval.ITmfStateInterval;
2757import org.eclipse.linuxtools.tmf.core.statesystem.ITmfStateSystem;
2758import org.eclipse.linuxtools.tmf.core.statevalue.ITmfStateValue;
2759import org.eclipse.linuxtools.tmf.core.trace.ITmfTrace;
2760
2761/**
2762 * Class showing examples of state system queries.
2763 *
2764 * @author Alexandre Montplaisir
2765 */
2766public class QueryExample {
2767
2768 private final ITmfStateSystem ss;
2769
2770 /**
2771 * Constructor
2772 *
2773 * @param trace
2774 * Trace that this "view" will display.
2775 */
2776 public QueryExample(ITmfTrace trace) {
2777 ss = trace.getStateSystems().get(MyTraceType.STATE_ID);
2778 }
2779
2780 /**
2781 * Example method of querying one attribute in the state system.
2782 *
2783 * We pass it a cpu and a timestamp, and it returns us if that cpu was
2784 * executing a process (true/false) at that time.
2785 *
2786 * @param cpu
2787 * The CPU to check
2788 * @param timestamp
2789 * The timestamp of the query
2790 * @return True if the CPU was running, false otherwise
2791 */
2792 public boolean cpuIsRunning(int cpu, long timestamp) {
2793 try {
2794 int quark = ss.getQuarkAbsolute("CPUs", String.valueOf(cpu), "Status");
2795 ITmfStateValue value = ss.querySingleState(timestamp, quark).getStateValue();
2796
2797 if (value.equals(MyStateProvider.RUNNING)) {
2798 return true;
2799 }
2800
2801 /*
2802 * Since at this level we have no guarantee on the contents of the state
2803 * system, it's important to handle these cases correctly.
2804 */
2805 } catch (AttributeNotFoundException e) {
2806 /*
2807 * Handle the case where the attribute does not exist in the state
2808 * system (no CPU with this number, etc.)
2809 */
2810 ...
2811 } catch (TimeRangeException e) {
2812 /*
2813 * Handle the case where 'timestamp' is outside of the range of the
2814 * history.
2815 */
2816 ...
2817 } catch (StateSystemDisposedException e) {
2818 /*
2819 * Handle the case where the state system is being disposed. If this
2820 * happens, it's normally when shutting down, so the view can just
2821 * return immediately and wait it out.
2822 */
2823 }
2824 return false;
2825 }
2826
2827
2828 /**
2829 * Example method of using a full query.
2830 *
2831 * We pass it a timestamp, and it returns us how many CPUs were executing a
2832 * process at that moment.
2833 *
2834 * @param timestamp
2835 * The target timestamp
2836 * @return The amount of CPUs that were running at that time
2837 */
2838 public int getNbRunningCpus(long timestamp) {
2839 int count = 0;
2840
2841 try {
2842 /* Get the list of the quarks we are interested in. */
2843 List<Integer> quarks = ss.getQuarks("CPUs", "*", "Status");
2844
2845 /*
2846 * Get the full state at our target timestamp (it's better than
2847 * doing an arbitrary number of single queries).
2848 */
2849 List<ITmfStateInterval> state = ss.queryFullState(timestamp);
2850
2851 /* Look at the value of the state for each quark */
2852 for (Integer quark : quarks) {
2853 ITmfStateValue value = state.get(quark).getStateValue();
2854 if (value.equals(MyStateProvider.RUNNING)) {
2855 count++;
2856 }
2857 }
2858
2859 } catch (TimeRangeException e) {
2860 /*
2861 * Handle the case where 'timestamp' is outside of the range of the
2862 * history.
2863 */
2864 ...
2865 } catch (StateSystemDisposedException e) {
2866 /* Handle the case where the state system is being disposed. */
2867 ...
2868 }
2869 return count;
2870 }
2871}
2872</pre>
2873
This page took 0.139055 seconds and 5 git commands to generate.