Commit | Line | Data |
---|---|---|
b1ea73b5 MK |
1 | /******************************************************************************* |
2 | * Copyright (c) 2015 Ericsson | |
3 | * | |
4 | * All rights reserved. This program and the accompanying materials | |
5 | * are made available under the terms of the Eclipse Public License v1.0 | |
6 | * which accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
8 | *******************************************************************************/ | |
9 | ||
10 | package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl; | |
11 | ||
12 | import java.util.List; | |
13 | ||
14 | import org.antlr.runtime.tree.CommonTree; | |
15 | import org.eclipse.tracecompass.ctf.core.event.CTFClock; | |
16 | import org.eclipse.tracecompass.ctf.parser.CTFParser; | |
17 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser; | |
18 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException; | |
19 | ||
20 | /** | |
21 | * Clock metadata allows to describe the clock topology of the system, as well | |
22 | * as to detail each clock parameter. In absence of clock description, it is | |
23 | * assumed that all fields named timestamp use the same clock source, which | |
24 | * increments once per nanosecond. | |
25 | * <p> | |
26 | * Describing a clock and how it is used by streams is threefold: first, the | |
27 | * clock and clock topology should be described in a clock description block, | |
28 | * e.g.: | |
29 | * | |
30 | * <pre> | |
31 | clock { | |
32 | name = cycle_counter_sync; | |
33 | uuid = "62189bee-96dc-11e0-91a8-cfa3d89f3923"; | |
34 | description = "Cycle counter synchronized across CPUs"; | |
35 | freq = 1000000000; // frequency, in Hz | |
36 | // precision in seconds is: 1000 * (1/freq) | |
37 | precision = 1000; | |
38 | ||
39 | // clock value offset from Epoch is: | |
40 | // offset_s + (offset * (1/freq)) | |
41 | ||
42 | offset_s = 1326476837; | |
43 | offset = 897235420; | |
44 | absolute = FALSE; | |
45 | }; | |
46 | * </pre> | |
47 | * | |
48 | * The mandatory name field specifies the name of the clock identifier, which | |
49 | * can later be used as a reference. The optional field uuid is the unique | |
50 | * identifier of the clock. It can be used to correlate different traces that | |
51 | * use the same clock. An optional textual description string can be added with | |
52 | * the description field. The freq field is the initial frequency of the clock, | |
53 | * in Hz. If the freq field is not present, the frequency is assumed to be | |
54 | * 1000000000 (providing clock increment of 1 ns). The optional precision field | |
55 | * details the uncertainty on the clock measurements, in (1/freq) units. The | |
56 | * offset_s and offset fields indicate the offset from POSIX.1 Epoch, 1970-01-01 | |
57 | * 00:00:00 +0000 (UTC), to the zero of value of the clock. The offset_s field | |
58 | * is in seconds. The offset field is in (1/freq) units. If any of the offset_s | |
59 | * or offset field is not present, it is assigned the 0 value. The field | |
60 | * absolute is TRUE if the clock is a global reference across different clock | |
61 | * UUID (e.g. NTP time). Otherwise, absolute is FALSE, and the clock can be | |
62 | * considered as synchronized only with other clocks that have the same UUID. | |
63 | * <p> | |
64 | * Secondly, a reference to this clock should be added within an integer type: | |
65 | * | |
66 | * <pre> | |
67 | typealias integer { | |
68 | size = 64; align = 1; signed = false; | |
69 | map = clock.cycle_counter_sync.value; | |
70 | } := uint64_ccnt_t; | |
71 | * </pre> | |
72 | * | |
73 | * Thirdly, stream declarations can reference the clock they use as a timestamp | |
74 | * source: | |
75 | * | |
76 | * <pre> | |
77 | struct packet_context { | |
78 | uint64_ccnt_t ccnt_begin; | |
79 | uint64_ccnt_t ccnt_end; | |
80 | // ... | |
81 | }; | |
82 | ||
83 | stream { | |
84 | // ... | |
85 | event.header := struct { | |
86 | uint64_ccnt_t timestamp; | |
87 | // ... | |
88 | }; | |
89 | packet.context := struct packet_context; | |
90 | }; | |
91 | * </pre> | |
92 | * | |
93 | * For a N-bit integer type referring to a clock, if the integer overflows | |
94 | * compared to the N low order bits of the clock prior value found in the same | |
95 | * stream, then it is assumed that one, and only one, overflow occurred. It is | |
96 | * therefore important that events encoding time on a small number of bits | |
97 | * happen frequently enough to detect when more than one N-bit overflow occurs. | |
98 | * <p> | |
99 | * In a packet context, clock field names ending with _begin and _end have a | |
100 | * special meaning: this refers to the timestamps at, respectively, the | |
101 | * beginning and the end of each packet. | |
102 | * | |
103 | * @author Matthew Khouzam - Initial API and implementation | |
104 | * @author Efficios (documentation) | |
105 | * | |
106 | */ | |
107 | public class ClockParser implements ICommonTreeParser { | |
108 | ||
109 | /** | |
110 | * Instance | |
111 | */ | |
112 | public static final ClockParser INSTANCE = new ClockParser(); | |
113 | ||
114 | private ClockParser() { | |
115 | } | |
116 | ||
117 | @Override | |
118 | public CTFClock parse(CommonTree clock, ICommonTreeParserParameter unused) throws ParseException { | |
119 | List<CommonTree> children = clock.getChildren(); | |
120 | CTFClock ctfClock = new CTFClock(); | |
121 | for (CommonTree child : children) { | |
122 | final String key = child.getChild(0).getChild(0).getChild(0).getText(); | |
123 | final CommonTree value = (CommonTree) child.getChild(1).getChild(0).getChild(0); | |
124 | final int type = value.getType(); | |
125 | final String text = value.getText(); | |
126 | switch (type) { | |
127 | case CTFParser.INTEGER: | |
128 | case CTFParser.DECIMAL_LITERAL: | |
129 | /* | |
130 | * Not a pretty hack, this is to make sure that there is no | |
131 | * number overflow due to 63 bit integers. The offset should | |
132 | * only really be an issue in the year 2262. the tracer in C/ASM | |
133 | * can write an offset in an unsigned 64 bit long. In java, the | |
134 | * last bit, being set to 1 will be read as a negative number, | |
135 | * but since it is too big a positive it will throw an | |
136 | * exception. this will happen in 2^63 ns from 1970. Therefore | |
137 | * 293 years from 1970 | |
138 | */ | |
139 | Long numValue; | |
140 | try { | |
141 | numValue = Long.parseLong(text); | |
142 | } catch (NumberFormatException e) { | |
143 | throw new ParseException("Number conversion issue with " + text, e); //$NON-NLS-1$ | |
144 | } | |
145 | ctfClock.addAttribute(key, numValue); | |
146 | break; | |
147 | default: | |
148 | ctfClock.addAttribute(key, text); | |
149 | } | |
150 | ||
151 | } | |
152 | return ctfClock; | |
153 | ||
154 | } | |
155 | ||
156 | } |