ctf.core: Implement parsing of clock fragments Add logic to parse CTF2 clock fragments and therefore allow for timestamp readings in CTF2. This implementation can be tested with a modified version of [1] that will be shared (updated to include CTF2-SPECRC-7.0 terminology) and can be compared with the equivalent CTF1 trace [2]. Babeltrace has yet to share tests that include clock origins, so those cannot be tested yet. An additional change was made to remove the datastream TODO that was left over from a previous patch. [1]https://review.lttng.org/plugins/gitiles/babeltrace/+/refs/heads/ctf2/tests/data/ctf-traces/2/succeed/barectf-event-before-packet/ [2]https://review.lttng.org/plugins/gitiles/babeltrace/+/refs/heads/ctf2/tests/data/ctf-traces/1/succeed/barectf-event-before-packet/ Change-Id: I46c2de5305b72ce8e4ef4834708b5887bd811bfc Signed-off-by: Sehr Moosabhoy <sehr.moosabhoy@ericsson.com> Reviewed-on: https://git.eclipse.org/r/c/tracecompass/org.eclipse.tracecompass/+/203658 Tested-by: Marco Miller <marco.miller@ericsson.com> Tested-by: Trace Compass Bot <tracecompass-bot@eclipse.org> Reviewed-by: Marco Miller <marco.miller@ericsson.com>
diff --git a/ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/trace/IOstructgenTest.java b/ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/trace/IOstructgenTest.java index 6be7e95..aa1a8d2 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/trace/IOstructgenTest.java +++ b/ctf/org.eclipse.tracecompass.ctf.core.tests/src/org/eclipse/tracecompass/ctf/core/tests/trace/IOstructgenTest.java
@@ -312,11 +312,122 @@ + " \"type\": \"trace-class\"\n" + "}\n"; + private static final String jsonClockFragment = Utils.RECORD_SEPARATOR + "{\n" + + " \"frequency\": 1000000000,\n" + + " \"name\": \"default\",\n" + + " \"offset-from-origin\": {\n" + + " \"cycles\": 0,\n" + + " \"seconds\": 1434072888\n" + + " },\n" + + " \"origin\": \"unix-epoch\", \n" + + " \"type\": \"clock-class\"\n" + + "}\n"; + private static final String jsonEmptyDataStream = Utils.RECORD_SEPARATOR + "{\n" + " \"type\": \"data-stream-class\"\n" + "}"; + private static final String jsonClockedDataStream = Utils.RECORD_SEPARATOR + + "{\n" + + " \"default-clock-class-name\": \"default\",\n" + + " \"event-record-header-field-class\": {\n" + + " \"member-classes\": [\n" + + " {\n" + + " \"field-class\": {\n" + + " \"alignment\": 64,\n" + + " \"byte-order\": \"little-endian\",\n" + + " \"length\": 64,\n" + + " \"roles\": [\n" + + " \"default-clock-timestamp\"\n" + + " ],\n" + + " \"type\": \"fixed-length-unsigned-integer\"\n" + + " },\n" + + " \"name\": \"timestamp\"\n" + + " },\n" + + " {\n" + + " \"field-class\": {\n" + + " \"alignment\": 16,\n" + + " \"byte-order\": \"little-endian\",\n" + + " \"length\": 16,\n" + + " \"roles\": [\n" + + " \"event-record-class-id\"\n" + + " ],\n" + + " \"type\": \"fixed-length-unsigned-integer\"\n" + + " },\n" + + " \"name\": \"id\"\n" + + " }\n" + + " ],\n" + + " \"type\": \"structure\"\n" + + " },\n" + + " \"packet-context-field-class\": {\n" + + " \"member-classes\": [\n" + + " {\n" + + " \"field-class\": {\n" + + " \"alignment\": 64,\n" + + " \"byte-order\": \"little-endian\",\n" + + " \"length\": 64,\n" + + " \"roles\": [\n" + + " \"default-clock-timestamp\"\n" + + " ],\n" + + " \"type\": \"fixed-length-unsigned-integer\"\n" + + " },\n" + + " \"name\": \"timestamp_begin\"\n" + + " },\n" + + " {\n" + + " \"field-class\": {\n" + + " \"alignment\": 64,\n" + + " \"byte-order\": \"little-endian\",\n" + + " \"length\": 64,\n" + + " \"roles\": [\n" + + " \"packet-end-default-clock-timestamp\"\n" + + " ],\n" + + " \"type\": \"fixed-length-unsigned-integer\"\n" + + " },\n" + + " \"name\": \"timestamp_end\"\n" + + " },\n" + + " {\n" + + " \"field-class\": {\n" + + " \"alignment\": 32,\n" + + " \"byte-order\": \"little-endian\",\n" + + " \"length\": 32,\n" + + " \"roles\": [\n" + + " \"packet-total-length\"\n" + + " ],\n" + + " \"type\": \"fixed-length-unsigned-integer\"\n" + + " },\n" + + " \"name\": \"packet_size\"\n" + + " },\n" + + " {\n" + + " \"field-class\": {\n" + + " \"alignment\": 32,\n" + + " \"byte-order\": \"little-endian\",\n" + + " \"length\": 32,\n" + + " \"roles\": [\n" + + " \"packet-content-length\"\n" + + " ],\n" + + " \"type\": \"fixed-length-unsigned-integer\"\n" + + " },\n" + + " \"name\": \"content_size\"\n" + + " },\n" + + " {\n" + + " \"field-class\": {\n" + + " \"alignment\": 32,\n" + + " \"byte-order\": \"little-endian\",\n" + + " \"length\": 32,\n" + + " \"roles\": [\n" + + " \"discarded-event-record-counter-snapshot\"\n" + + " ],\n" + + " \"type\": \"fixed-length-unsigned-integer\"\n" + + " },\n" + + " \"name\": \"events_discarded\"\n" + + " }\n" + + " ],\n" + + " \"type\": \"structure\"\n" + + " },\n" + + " \"type\": \"data-stream-class\"\n" + + "}\n"; + private static final String jsonPacketContextDataStream = Utils.RECORD_SEPARATOR + "{\n" + " \"packet-context-field-class\": {\n" @@ -351,6 +462,26 @@ + " \"type\": \"data-stream-class\"\n" + "}\n"; + private static final String jsonClockedEventRecord = Utils.RECORD_SEPARATOR + + "{\n" + + " \"name\": \"simple_uint32\",\n" + + " \"payload-field-class\": {\n" + + " \"member-classes\": [\n" + + " {\n" + + " \"field-class\": {\n" + + " \"alignment\": 32,\n" + + " \"byte-order\": \"little-endian\",\n" + + " \"length\": 32,\n" + + " \"type\": \"fixed-length-unsigned-integer\"\n" + + " },\n" + + " \"name\": \"value\"\n" + + " }\n" + + " ],\n" + + " \"type\": \"structure\"\n" + + " },\n" + + " \"type\": \"event-record-class\"" + + "}"; + private static final String jsonEventRecord = Utils.RECORD_SEPARATOR + "{\n" + " \"name\": \"string\",\n" @@ -386,6 +517,8 @@ + jsonEmptyDataStream + jsonEventRecord; private static final String packetContextJson = jsonPreamble + jsonPacketHeaderTrace + jsonPacketContextDataStream + jsonEventRecord; + private static final String clockedJson = jsonPreamble + jsonPacketHeaderTrace + jsonClockFragment + + jsonClockedDataStream + jsonClockedEventRecord; static final String tempTraceDir = CtfCoreTestPlugin.getTemporaryDirPath() + File.separator + "tempTrace"; @@ -647,4 +780,17 @@ trace = new CTFTrace(tempTraceDir); assertNotNull(trace); } + + /** + * Test with clocked trace + * + * @throws CTFException + * something wrong happened + */ + @Test + public void jsonClockedTest() throws CTFException { + createDummyTrace(clockedJson); + trace = new CTFTrace(tempTraceDir); + assertNotNull(trace); + } }
diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/EventDeclaration.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/EventDeclaration.java index ef0a2e3..f8a8cea 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/EventDeclaration.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/EventDeclaration.java
@@ -42,6 +42,7 @@ import org.eclipse.tracecompass.ctf.core.trace.ICTFPacketDescriptor; import org.eclipse.tracecompass.internal.ctf.core.event.types.composite.EventHeaderDefinition; import org.eclipse.tracecompass.internal.ctf.core.trace.CTFStream; +import org.eclipse.tracecompass.internal.ctf.core.utils.JsonMetadataStrings; import com.google.common.collect.ImmutableList; @@ -128,7 +129,17 @@ StructDefinition streamEventContext = streamEventContextDecl != null ? streamEventContextDecl.createDefinition(trace, ILexicalScope.STREAM_EVENT_CONTEXT, input) : null; StructDefinition eventContext = fContext != null ? fContext.createFieldDefinition(eventHeaderDef, trace, ILexicalScope.CONTEXT, input) : null; StructDefinition eventPayload = fFields != null ? fFields.createFieldDefinition(eventHeaderDef, trace, ILexicalScope.FIELDS, input) : null; - long timestamp = calculateTimestamp(eventHeaderDef, prevTimestamp, eventPayload, eventContext); + String timestampVariable = null; + long timestamp; + if (trace != null) { + timestampVariable = Long.valueOf(2).equals(trace.getMajor()) ? JsonMetadataStrings.DEFAULT_CLOCK_TIMESTAMP : CTFStrings.TIMESTAMP; + timestamp = calculateTimestamp(eventHeaderDef, prevTimestamp, eventPayload, eventContext, timestampVariable); + } else { + timestamp = calculateTimestamp(eventHeaderDef, prevTimestamp, eventPayload, eventContext, CTFStrings.TIMESTAMP); + if (timestamp == 0) { + calculateTimestamp(eventHeaderDef, prevTimestamp, eventPayload, eventContext, JsonMetadataStrings.DEFAULT_CLOCK_TIMESTAMP); + } + } int cpu = (int) packetDescriptor.getTargetId(); return new EventDefinition( @@ -143,7 +154,7 @@ packetDescriptor); } - private static long calculateTimestamp(@Nullable ICompositeDefinition eventHeaderDef, long prevTimestamp, StructDefinition eventPayload, StructDefinition eventContext) throws CTFIOException { + private static long calculateTimestamp(@Nullable ICompositeDefinition eventHeaderDef, long prevTimestamp, StructDefinition eventPayload, StructDefinition eventContext, String timestampVariable) throws CTFIOException { long timestamp = 0; Definition def = null; if (eventHeaderDef instanceof EventHeaderDefinition) { @@ -152,15 +163,16 @@ def = eventHeaderDefinition; } else if (eventHeaderDef instanceof StructDefinition) { StructDefinition structDefinition = (StructDefinition) eventHeaderDef; - def = structDefinition.lookupDefinition(CTFStrings.TIMESTAMP); + def = structDefinition.lookupDefinition(timestampVariable); } else if (eventHeaderDef != null) { throw new CTFIOException("Event header def is not a Struct or an Event Header"); //$NON-NLS-1$ } - if (def == null && eventPayload != null) { - def = eventPayload.lookupDefinition(CTFStrings.TIMESTAMP); + + if (def == null && eventPayload != null && eventPayload.getDefinition(timestampVariable) != null) { + def = eventPayload.lookupDefinition(timestampVariable); } - if (def == null && eventContext != null) { - def = eventContext.lookupDefinition(CTFStrings.TIMESTAMP); + if (def == null && eventContext != null && eventContext.getDefinition(timestampVariable) != null) { + def = eventContext.lookupDefinition(timestampVariable); } if (def instanceof IntegerDefinition) { IntegerDefinition timestampDef = (IntegerDefinition) def;
diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java index 1063e7d..820747e 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java
@@ -156,7 +156,7 @@ hasStreams = true; } else if (CTFParser.tokenNames[CTFParser.EVENT].equals(type) || JsonMetadataStrings.FRAGMENT_EVENT_RECORD.equals(type)) { events.add(child); - } else if (CTFParser.tokenNames[CTFParser.CLOCK].equals(type)) { + } else if (CTFParser.tokenNames[CTFParser.CLOCK].equals(type) || JsonMetadataStrings.FRAGMENT_CLOCK.equals(type)) { CTFClock ctfClock = ClockParser.INSTANCE.parse(child, null); String nameValue = ctfClock.getName(); fTrace.addClock(nameValue, ctfClock); @@ -167,9 +167,6 @@ } else if (JsonMetadataStrings.FRAGMENT_PREAMBLE.equals(type)) { // FIXME: support Preamble fragment (CTF2 spec 5.5) // https://diamon.org/ctf/files/CTF2-SPECRC-7.0rA.html#preamble-frag - } else if (JsonMetadataStrings.FRAGMENT_DATA_STREAM.equals(type)) { - // FIXME: support Data Stream fragment (CTF2 spec 5.9) - // https://diamon.org/ctf/files/CTF2-SPECRC-7.0rA.html#dsc-frag } else { throw childTypeError(child); }
diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonClockMetadataNode.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonClockMetadataNode.java index 02c84d9..1f2db48 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonClockMetadataNode.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonClockMetadataNode.java
@@ -15,6 +15,7 @@ import org.eclipse.tracecompass.internal.ctf.core.event.types.ICTFMetadataNode; +import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.annotations.SerializedName; @@ -30,9 +31,9 @@ @SerializedName("name") private final String fName; @SerializedName("frequency") - private final int fFrequency; + private final Long fFrequency; @SerializedName("origin") - private JsonObject fOrigin; + private JsonElement fOrigin; @SerializedName("offset-from-origin") private JsonObject fOffset; @SerializedName("precision") @@ -54,7 +55,7 @@ * @param frequency * the frequency of the clock described in this node */ - public JsonClockMetadataNode(ICTFMetadataNode parent, String type, String value, String name, int frequency) { + public JsonClockMetadataNode(ICTFMetadataNode parent, String type, String value, String name, Long frequency) { super(parent, type, value); this.fName = name; this.fFrequency = frequency; @@ -65,7 +66,7 @@ * * @return the frequency */ - public int getFrequency() { + public Long getFrequency() { return fFrequency; } @@ -74,7 +75,7 @@ * * @return the origin */ - public Object getOrigin() { + public JsonElement getOrigin() { return fOrigin; }
diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonClockOriginMetadataNode.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonClockOriginMetadataNode.java new file mode 100644 index 0000000..0ac01bc --- /dev/null +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/JsonClockOriginMetadataNode.java
@@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2023 Ericsson + * + * All rights reserved. This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 which + * accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Sehr Moosabhoy - Initial implementation + *******************************************************************************/ +package org.eclipse.tracecompass.internal.ctf.core.event.metadata; + +import org.eclipse.tracecompass.internal.ctf.core.event.types.ICTFMetadataNode; + +import com.google.gson.annotations.SerializedName; + +/** + * Node to store the clock origin object for CTF2 traces + * + * @author Sehr Moosabhoy + */ +public class JsonClockOriginMetadataNode extends CTFJsonMetadataNode { + + @SerializedName("namespace") + private String fNamespace; + @SerializedName("name") + private final String fName; + @SerializedName("uid") + private final String fUid; + + /** + * Constructor for a JsonClockOriginMetadataNode + * + * @param parent + * the parent of this node + * @param type + * the type of this node + * @param value + * the value of this node + * @param name + * the name of the clock origin described in this node + * @param uid + * the uid of the clock origin described in this node + */ + public JsonClockOriginMetadataNode(ICTFMetadataNode parent, String type, String value, String name, String uid) { + super(parent, type, value); + fName = name; + fUid = uid; + } + + /** + * Get the namespace of the node + * + * @return the namespace + */ + public String getNamespace() { + return fNamespace; + } + + /** + * Get the name of the node + * + * @return the name + */ + public String getName() { + return fName; + } + + /** + * Get the uid of the node + * + * @return the uid + */ + public String getUid() { + return fUid; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof JsonClockOriginMetadataNode) { + JsonClockOriginMetadataNode clock = (JsonClockOriginMetadataNode) obj; + if (fName.equals(clock.getName()) && fNamespace.equals(clock.getNamespace()) && fUid.equals(clock.getUid())) { + return true; + } + } + return false; + } + + @Override + public int hashCode() { + return super.hashCode(); + } +}
diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/ClockParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/ClockParser.java index e82cd54..65b3dcd 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/ClockParser.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/ClockParser.java
@@ -18,9 +18,12 @@ 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.JsonClockMetadataNode; import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException; import org.eclipse.tracecompass.internal.ctf.core.event.types.ICTFMetadataNode; +import com.google.gson.JsonObject; + /** * 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 @@ -110,6 +113,17 @@ */ public final class ClockParser implements ICommonTreeParser { + private static final String NAME = "name"; //$NON-NLS-1$ + private static final String FREQUENCY = "freq"; //$NON-NLS-1$ + private static final String ORIGIN = "origin"; //$NON-NLS-1$ + private static final String SECONDS = "seconds"; //$NON-NLS-1$ + private static final String CYCLES = "cycles"; //$NON-NLS-1$ + private static final String OFFSET = "offset"; //$NON-NLS-1$ + private static final String OFFSET_S = "offset_s"; //$NON-NLS-1$ + private static final String PRECISION = "precision"; //$NON-NLS-1$ + private static final String DESCRIPTION = "description"; //$NON-NLS-1$ + private static final String UNIX_EPOCH = "unix-epoch"; //$NON-NLS-1$ + /** * Instance */ @@ -120,39 +134,62 @@ @Override public CTFClock parse(ICTFMetadataNode clock, ICommonTreeParserParameter unused) throws ParseException { - List<ICTFMetadataNode> children = clock.getChildren(); CTFClock ctfClock = new CTFClock(); - for (ICTFMetadataNode child : children) { - final String key = child.getChild(0).getChild(0).getChild(0).getText(); - final ICTFMetadataNode value = child.getChild(1).getChild(0).getChild(0); - final String type = value.getType(); - final String text = value.getText(); - if (CTFParser.tokenNames[CTFParser.INTEGER].equals(type) || CTFParser.tokenNames[CTFParser.DECIMAL_LITERAL].equals(type)) { - /* - * 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); - } else { - ctfClock.addAttribute(key, text); - } + if (clock instanceof JsonClockMetadataNode) { + JsonClockMetadataNode jsonClock = (JsonClockMetadataNode) clock; + ctfClock.addAttribute(FREQUENCY, jsonClock.getFrequency()); + ctfClock.addAttribute(NAME, jsonClock.getName()); + ctfClock.addAttribute(PRECISION, jsonClock.getPrecision()); + if (jsonClock.getDescription() != null) { + ctfClock.addAttribute(DESCRIPTION, jsonClock.getPrecision()); + } + JsonObject offset = jsonClock.getOffset(); + if (offset.has(SECONDS) && offset.has(CYCLES)) { + Long seconds = offset.get(SECONDS).getAsLong(); + Long cycles = offset.get(CYCLES).getAsLong(); + ctfClock.addAttribute(OFFSET, cycles); + ctfClock.addAttribute(OFFSET_S, seconds); + } + if (jsonClock.getOrigin() != null) { + if (jsonClock.getOrigin().isJsonObject()) { + ctfClock.addAttribute(ORIGIN, jsonClock.getOrigin().getAsJsonObject().get(NAME).getAsString()); + } else if (jsonClock.getOrigin().getAsString().equals(UNIX_EPOCH)) { + ctfClock.addAttribute(ORIGIN, UNIX_EPOCH); + } + } + } else { + List<ICTFMetadataNode> children = clock.getChildren(); + for (ICTFMetadataNode child : children) { + String key = child.getChild(0).getChild(0).getChild(0).getText(); + ICTFMetadataNode value = child.getChild(1).getChild(0).getChild(0); + String type = value.getType(); + String text = value.getText(); + + if (CTFParser.tokenNames[CTFParser.INTEGER].equals(type) || CTFParser.tokenNames[CTFParser.DECIMAL_LITERAL].equals(type)) { + /* + * 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 large as a positive + * number 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); + } else { + ctfClock.addAttribute(key, text); + } + } } return ctfClock; - } - }