| 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 final 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 | } |