1 /*******************************************************************************
2 * Copyright (c) 2011, 2014 Ericsson, Ecole Polytechnique de Montreal and others
4 * All rights reserved. This program and the accompanying materials are made
5 * available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
9 * Contributors: Matthew Khouzam - Initial API and implementation
10 * Contributors: Simon Marchi - Initial API and implementation
11 *******************************************************************************/
13 package org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
;
15 import java
.util
.HashMap
;
19 import org
.eclipse
.jdt
.annotation
.NonNull
;
20 import org
.eclipse
.jdt
.annotation
.Nullable
;
21 import org
.eclipse
.tracecompass
.common
.core
.NonNullUtils
;
22 import org
.eclipse
.tracecompass
.ctf
.core
.CTFException
;
23 import org
.eclipse
.tracecompass
.ctf
.core
.CTFStrings
;
24 import org
.eclipse
.tracecompass
.ctf
.core
.event
.EventDefinition
;
25 import org
.eclipse
.tracecompass
.ctf
.core
.event
.IEventDeclaration
;
26 import org
.eclipse
.tracecompass
.ctf
.core
.event
.io
.BitBuffer
;
27 import org
.eclipse
.tracecompass
.ctf
.core
.event
.scope
.ILexicalScope
;
28 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.Definition
;
29 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.ICompositeDefinition
;
30 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.IntegerDefinition
;
31 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.StructDeclaration
;
32 import org
.eclipse
.tracecompass
.ctf
.core
.event
.types
.StructDefinition
;
33 import org
.eclipse
.tracecompass
.ctf
.core
.trace
.CTFIOException
;
34 import org
.eclipse
.tracecompass
.ctf
.core
.trace
.CTFStream
;
35 import org
.eclipse
.tracecompass
.ctf
.core
.trace
.CTFStreamInputReader
;
36 import org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.types
.composite
.EventHeaderDefinition
;
39 * Representation of one type of event. A bit like "int" or "long" but for trace
42 public class EventDeclaration
implements IEventDeclaration
{
44 // ------------------------------------------------------------------------
46 // ------------------------------------------------------------------------
54 * Event context structure declaration
56 private StructDeclaration fContext
= null;
59 * Event fields structure declaration
61 private StructDeclaration fFields
= null;
64 * Stream to which belongs this event.
66 private CTFStream fStream
= null;
69 * Loglevel of an event
71 private long fLogLevel
;
73 /** Map of this event type's custom CTF attributes */
74 private final Map
<String
, String
> fCustomAttributes
= new HashMap
<>();
76 private int fId
= (int) UNSET_EVENT_ID
;
78 // ------------------------------------------------------------------------
80 // ------------------------------------------------------------------------
83 * Default constructor. Use the setters afterwards to set the fields
86 public EventDeclaration() {
90 * Creates an instance of EventDefinition corresponding to this declaration.
92 * @param streamInputReader
93 * The StreamInputReader for which this definition is created.
94 * @param eventHeaderDef
95 * The event header definition
97 * the bitbuffer input source
98 * @param prevTimestamp
99 * The timestamp when the event was taken
100 * @return A new EventDefinition.
101 * @throws CTFException
102 * As a bitbuffer is used to read, it could have wrapped
105 public EventDefinition
createDefinition(CTFStreamInputReader streamInputReader
, ICompositeDefinition eventHeaderDef
, @NonNull BitBuffer input
, long prevTimestamp
) throws CTFException
{
106 StructDeclaration streamEventContextDecl
= streamInputReader
.getStreamEventContextDecl();
107 StructDefinition streamEventContext
= streamEventContextDecl
!= null ? streamEventContextDecl
.createDefinition(fStream
.getTrace(), ILexicalScope
.STREAM_EVENT_CONTEXT
, input
) : null;
108 ICompositeDefinition packetContext
= streamInputReader
.getPacketReader().getCurrentPacketEventHeader();
109 StructDefinition eventContext
= fContext
!= null ? fContext
.createFieldDefinition(eventHeaderDef
, fStream
.getTrace(), ILexicalScope
.CONTEXT
, input
) : null;
110 StructDefinition eventPayload
= fFields
!= null ? fFields
.createFieldDefinition(eventHeaderDef
, fStream
.getTrace(), ILexicalScope
.FIELDS
, input
) : null;
111 long timestamp
= calculateTimestamp(eventHeaderDef
, prevTimestamp
, eventPayload
, eventContext
);
113 return new EventDefinition(
115 streamInputReader
.getCPU(),
124 private static long calculateTimestamp(@Nullable ICompositeDefinition eventHeaderDef
, long prevTimestamp
, StructDefinition eventPayload
, StructDefinition eventContext
) throws CTFIOException
{
126 Definition def
= null;
127 if (eventHeaderDef
instanceof EventHeaderDefinition
) {
128 EventHeaderDefinition eventHeaderDefinition
= (EventHeaderDefinition
) eventHeaderDef
;
129 timestamp
= calculateTimestamp(eventHeaderDefinition
.getTimestamp(), eventHeaderDefinition
.getTimestampLength(), prevTimestamp
);
130 def
= eventHeaderDefinition
;
131 } else if (eventHeaderDef
instanceof StructDefinition
) {
132 StructDefinition structDefinition
= (StructDefinition
) eventHeaderDef
;
133 def
= structDefinition
.lookupDefinition(CTFStrings
.TIMESTAMP
);
134 } else if (eventHeaderDef
!= null) {
135 throw new CTFIOException("Event header def is not a Struct or an Event Header"); //$NON-NLS-1$
137 if (def
== null && eventPayload
!= null) {
138 def
= eventPayload
.lookupDefinition(CTFStrings
.TIMESTAMP
);
140 if (def
== null && eventContext
!= null) {
141 def
= eventContext
.lookupDefinition(CTFStrings
.TIMESTAMP
);
143 if (def
instanceof IntegerDefinition
) {
144 IntegerDefinition timestampDef
= (IntegerDefinition
) def
;
145 timestamp
= calculateTimestamp(timestampDef
, prevTimestamp
);
151 public EventDefinition
createDefinition(CTFStreamInputReader streamInputReader
, @NonNull BitBuffer input
, long timestamp
) throws CTFException
{
152 StructDeclaration streamEventContextDecl
= streamInputReader
.getStreamEventContextDecl();
153 StructDefinition streamEventContext
= streamEventContextDecl
!= null ? streamEventContextDecl
.createDefinition(fStream
.getTrace(), ILexicalScope
.STREAM_EVENT_CONTEXT
, input
) : null;
154 ICompositeDefinition packetContext
= streamInputReader
.getPacketReader().getCurrentPacketEventHeader();
155 StructDefinition eventContext
= fContext
!= null ? fContext
.createDefinition(fStream
.getTrace(), ILexicalScope
.CONTEXT
, input
) : null;
156 StructDefinition eventPayload
= fFields
!= null ? fFields
.createDefinition(fStream
.getTrace(), ILexicalScope
.FIELDS
, input
) : null;
158 // a bit lttng specific
159 // CTF doesn't require a timestamp,
160 // but it's passed to us
161 return new EventDefinition(
163 streamInputReader
.getCPU(),
172 // ------------------------------------------------------------------------
173 // Getters/Setters/Predicates
174 // ------------------------------------------------------------------------
177 * Sets a name for an event Declaration
182 public void setName(String name
) {
187 public String
getName() {
192 * Sets the context for an event declaration (see CTF specification)
195 * the context in structdeclaration format
197 public void setContext(StructDeclaration context
) {
202 * Sets the fields of an event declaration
205 * the fields in structdeclaration format
207 public void setFields(StructDeclaration fields
) {
212 public StructDeclaration
getFields() {
217 public StructDeclaration
getContext() {
222 * Sets the id of an event declaration
227 public void setId(long id
) {
228 if (id
< 0 || id
> Integer
.MAX_VALUE
) {
229 throw new IllegalArgumentException("id out of range"); //$NON-NLS-1$
235 public Long
getId() {
236 return Long
.valueOf(fId
);
240 * Faster get id assuming you have less than a billion event types
242 * @return the event id
249 * Sets the stream of an event declaration
254 public void setStream(CTFStream stream
) {
259 public CTFStream
getStream() {
264 * Is the name of the event declaration set
266 * @return is the name set?
268 public boolean nameIsSet() {
269 return fName
!= null;
275 * @return is the context set
277 public boolean contextIsSet() {
278 return fContext
!= null;
284 * @return Is the field set?
286 public boolean fieldsIsSet() {
287 return fFields
!= null;
293 * @return is the id set?
295 public boolean idIsSet() {
296 return (fId
!= UNSET_EVENT_ID
);
302 * @return is the stream set?
304 public boolean streamIsSet() {
305 return fStream
!= null;
309 public long getLogLevel() {
319 public void setLogLevel(long level
) {
324 public Set
<String
> getCustomAttributes() {
325 return fCustomAttributes
.keySet();
329 public String
getCustomAttribute(String key
) {
330 return fCustomAttributes
.get(key
);
334 * Sets a custom attribute value.
337 * the key of the attribute
339 * the value of the attribute
341 public void setCustomAttribute(String key
, String value
) {
342 fCustomAttributes
.put(key
, value
);
346 * Calculates the timestamp value of the event, possibly using the timestamp
347 * from the last event.
349 * @param timestampDef
350 * Integer definition of the timestamp.
351 * @return The calculated timestamp value.
353 private static long calculateTimestamp(IntegerDefinition timestampDef
, long lastTimestamp
) {
354 int len
= timestampDef
.getDeclaration().getLength();
355 final long value
= timestampDef
.getValue();
357 return calculateTimestamp(value
, len
, lastTimestamp
);
360 private static long calculateTimestamp(final long value
, int len
, long prevTimestamp
) {
363 long lastTimestamp
= prevTimestamp
;
365 * If the timestamp length is 64 bits, it is a full timestamp.
367 if (len
== Long
.SIZE
) {
368 lastTimestamp
= value
;
369 return lastTimestamp
;
373 * Bit mask to keep / remove all old / new bits.
375 majorasbitmask
= (1L << len
) - 1;
378 * If the new value is smaller than the corresponding bits of the last
379 * timestamp, we assume an overflow of the compact representation.
382 if (newval
< (lastTimestamp
& majorasbitmask
)) {
383 newval
= newval
+ (1L << len
);
386 /* Keep only the high bits of the old value */
387 lastTimestamp
= lastTimestamp
& ~majorasbitmask
;
389 /* Then add the low bits of the new value */
390 lastTimestamp
= lastTimestamp
+ newval
;
392 return lastTimestamp
;
395 // ------------------------------------------------------------------------
397 // ------------------------------------------------------------------------
400 public boolean equals(Object obj
) {
407 if (!(obj
instanceof EventDeclaration
)) {
410 EventDeclaration other
= (EventDeclaration
) obj
;
411 if (fId
!= (other
.fId
)) {
414 if (!NonNullUtils
.equalsNullable(fContext
, other
.fContext
)) {
417 if (!NonNullUtils
.equalsNullable(fFields
, other
.fFields
)) {
420 if (!NonNullUtils
.equalsNullable(fName
, other
.fName
)) {
423 if (!NonNullUtils
.equalsNullable(fStream
, other
.fStream
)) {
426 if (!fCustomAttributes
.equals(other
.fCustomAttributes
)) {
433 public int hashCode() {
434 final int prime
= 31;
436 result
= (prime
* result
)
437 + ((fContext
== null) ?
0 : fContext
.hashCode());
438 result
= (prime
* result
) + ((fFields
== null) ?
0 : fFields
.hashCode());
439 result
= (prime
* result
) + fId
;
440 result
= (prime
* result
) + ((fName
== null) ?
0 : fName
.hashCode());
441 result
= (prime
* result
) + ((fStream
== null) ?
0 : fStream
.hashCode());
442 result
= (prime
* result
) + fCustomAttributes
.hashCode();