/******************************************************************************* * Copyright (c) 2015 Ericsson * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl; import java.util.List; import org.antlr.runtime.tree.CommonTree; import org.eclipse.core.runtime.IStatus; import org.eclipse.tracecompass.ctf.core.event.CTFClock; import org.eclipse.tracecompass.ctf.parser.CTFParser; import org.eclipse.tracecompass.internal.ctf.core.Activator; import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser; import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException; /** * Clock metadata allows to describe the clock topology of the system, as well * as to detail each clock parameter. In absence of clock description, it is * assumed that all fields named timestamp use the same clock source, which * increments once per nanosecond. * <p> * Describing a clock and how it is used by streams is threefold: first, the * clock and clock topology should be described in a clock description block, * e.g.: * * <pre> clock { name = cycle_counter_sync; uuid = "62189bee-96dc-11e0-91a8-cfa3d89f3923"; description = "Cycle counter synchronized across CPUs"; freq = 1000000000; // frequency, in Hz // precision in seconds is: 1000 * (1/freq) precision = 1000; // clock value offset from Epoch is: // offset_s + (offset * (1/freq)) offset_s = 1326476837; offset = 897235420; absolute = FALSE; }; * </pre> * * The mandatory name field specifies the name of the clock identifier, which * can later be used as a reference. The optional field uuid is the unique * identifier of the clock. It can be used to correlate different traces that * use the same clock. An optional textual description string can be added with * the description field. The freq field is the initial frequency of the clock, * in Hz. If the freq field is not present, the frequency is assumed to be * 1000000000 (providing clock increment of 1 ns). The optional precision field * details the uncertainty on the clock measurements, in (1/freq) units. The * offset_s and offset fields indicate the offset from POSIX.1 Epoch, 1970-01-01 * 00:00:00 +0000 (UTC), to the zero of value of the clock. The offset_s field * is in seconds. The offset field is in (1/freq) units. If any of the offset_s * or offset field is not present, it is assigned the 0 value. The field * absolute is TRUE if the clock is a global reference across different clock * UUID (e.g. NTP time). Otherwise, absolute is FALSE, and the clock can be * considered as synchronized only with other clocks that have the same UUID. * <p> * Secondly, a reference to this clock should be added within an integer type: * * <pre> typealias integer { size = 64; align = 1; signed = false; map = clock.cycle_counter_sync.value; } := uint64_ccnt_t; * </pre> * * Thirdly, stream declarations can reference the clock they use as a timestamp * source: * * <pre> struct packet_context { uint64_ccnt_t ccnt_begin; uint64_ccnt_t ccnt_end; // ... }; stream { // ... event.header := struct { uint64_ccnt_t timestamp; // ... }; packet.context := struct packet_context; }; * </pre> * * For a N-bit integer type referring to a clock, if the integer overflows * compared to the N low order bits of the clock prior value found in the same * stream, then it is assumed that one, and only one, overflow occurred. It is * therefore important that events encoding time on a small number of bits * happen frequently enough to detect when more than one N-bit overflow occurs. * <p> * In a packet context, clock field names ending with _begin and _end have a * special meaning: this refers to the timestamps at, respectively, the * beginning and the end of each packet. * * @author Matthew Khouzam - Initial API and implementation * @author Efficios (documentation) * */ public final class ClockParser implements ICommonTreeParser { /** * Instance */ public static final ClockParser INSTANCE = new ClockParser(); private ClockParser() { } @Override public CTFClock parse(CommonTree clock, ICommonTreeParserParameter unused) throws ParseException { List<CommonTree> children = clock.getChildren(); CTFClock ctfClock = new CTFClock(); for (CommonTree child : children) { final String key = child.getChild(0).getChild(0).getChild(0).getText(); final CommonTree value = (CommonTree) child.getChild(1).getChild(0).getChild(0); final int type = value.getType(); final String text = value.getText(); switch (type) { case CTFParser.INTEGER: case CTFParser.DECIMAL_LITERAL: /* * Not a pretty hack, this is to make sure that there is no * number overflow due to 63 bit integers. The offset should * only really be an issue in the year 2262. the tracer in C/ASM * can write an offset in an unsigned 64 bit long. In java, the * last bit, being set to 1 will be read as a negative number, * but since it is too big a positive it will throw an * exception. this will happen in 2^63 ns from 1970. Therefore * 293 years from 1970 */ Long numValue; try { numValue = Long.parseLong(text); } catch (NumberFormatException e) { Activator.log(IStatus.WARNING, "Number conversion issue with " + text + ". Assigning " + key + " = 0."); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ numValue = Long.valueOf(0L); } ctfClock.addAttribute(key, numValue); break; default: ctfClock.addAttribute(key, text); } } return ctfClock; } }