blob: c1cbd3256cde2e7ef71956f588d078d6213c36a5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2014 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:
* Matthew Khouzam - Initial API and implementation
* Simon Delisle - Generate dummy trace
*******************************************************************************/
package org.eclipse.tracecompass.ctf.core.tests.trace;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.tracecompass.ctf.core.CTFException;
import org.eclipse.tracecompass.ctf.core.event.IEventDeclaration;
import org.eclipse.tracecompass.ctf.core.tests.CtfCoreTestPlugin;
import org.eclipse.tracecompass.ctf.core.trace.CTFTrace;
import org.eclipse.tracecompass.internal.ctf.core.event.EventDeclaration;
import org.eclipse.tracecompass.internal.ctf.core.event.metadata.IOStructGen;
import org.junit.Test;
/**
* Unit tests for {@link IOStructGen}
*
* @author Matthew Khouzam
*/
public class IOstructgenTest {
private static final String metadataDecs = "typealias integer { size = 8; align = 8; signed = false; } := uint8_t;\n"
+ "typealias integer { size = 16; align = 8; signed = false; } := uint16_t;\n"
+ "typealias integer { size = 32; align = 8; signed = false; } := uint32_t;\n"
+ "typealias integer { size = 64; align = 8; signed = false; } := uint64_t;\n"
+ "typealias integer { size = 64; align = 8; signed = false; } := unsigned long;\n"
+ "typealias integer { size = 5; align = 1; signed = false; } := uint5_t;\n"
+ "typealias integer { size = 27; align = 1; signed = false; } := uint27_t;\n"
+ "typealias integer { size = 32; align = 1; signed = true; base = decimal; } := int32_t;\n"
+ "typealias integer { size = 31; align = 1; signed = true; base = dec; } := int31_t;\n"
+ "typealias integer { size = 30; align = 1; signed = true; base = d; } := int30_t;\n"
+ "typealias integer { size = 29; align = 1; signed = true; base = i; } := int29_t;\n"
+ "typealias integer { size = 28; align = 1; signed = true; base = u; } := int28_t;\n"
+ "typealias integer { size = 27; align = 1; signed = true; base = hexadecimal; } := int27_t;\n"
+ "typealias integer { size = 26; align = 1; signed = true; base = hex; } := int26_t;\n"
+ "typealias integer { size = 25; align = 1; signed = true; base = x; } := int25_t;\n"
+ "typealias integer { size = 24; align = 1; signed = true; base = X; } := int24_t;\n"
+ "typealias integer { size = 23; align = 1; signed = true; base = p; } := int23_t;\n"
+ "typealias integer { size = 22; align = 1; signed = true; base = 16; } := int22_t;\n"
+ "typealias integer { size = 21; align = 1; signed = true; base = oct; } := int21_t;\n"
+ "typealias integer { size = 20; align = 1; signed = true; base = b; } := int20_t;\n"
+ "typealias integer { size = 19; align = 1; signed = true; base = octal; } := int19_t;\n"
+ "typealias integer { size = 18; align = 1; signed = true; base = o; } := int18_t;\n"
+ "typealias integer { size = 17; align = 1; signed = true; base = binary; } := int17_t;\n"
+ "\n"
+ "trace {\n"
+ " major = 1;\n"
+ " minor = 8;\n"
+ " uuid = \"b04d391b-e736-44c1-8d89-4bb438857f8d\";\n"
+ " byte_order = le;\n"
+ " packet.header := struct {\n"
+ " uint32_t magic;\n"
+ " uint8_t uuid[16];\n"
+ " uint32_t stream_id;\n" + " };\n" + "};\n" + "\n";
private static final String environmentMD = "env {\n"
+ " hostname = \"DemoSystem\";\n"
+ " vpid = 1337;\n"
+ " procname = \"demo\";\n"
+ " domain = \"autogenerated\";\n"
+ " tracer_name = \"tmf\";\n"
+ " tracer_major = 2;\n"
+ " tracer_minor = 0x01;\n"
+ " tracer_patchlevel = 0;\n"
+ "};\n" + "\n";
private static final String clockMD = "clock {\n" + " name = monotonic;\n"
+ " uuid = \"cbf9f42e-9be7-4798-a96f-11db556e2ebb\";\n"
+ " description = \"Monotonic Clock\";\n"
+ " freq = 1000000000; /* Frequency, in Hz */\n"
+ " /* clock value offset from Epoch is: offset * (1/freq) */\n"
+ " offset = 1350310657466295832;\n" + "};\n"
+ "\n";
private static final String ctfStart =
"typealias integer {\n"
+ " size = 27; align = 1; signed = false;\n"
+ " map = clock.monotonic.value;\n"
+ "} := uint27_clock_monotonic_t;\n"
+ "\n"
+ "typealias integer {\n"
+ " size = 32; align = 8; signed = false;\n"
+ " map = clock.monotonic.value;\n"
+ "} := uint32_clock_monotonic_t;\n"
+ "\n"
+ "typealias integer {\n"
+ " size = 64; align = 8; signed = false;\n"
+ " map = clock.monotonic.value;\n"
+ "} := uint64_clock_monotonic_t;\n"
+ "\n";
private static final String ctfHeaders =
"struct packet_context {\n"
+ " uint64_clock_monotonic_t timestamp_begin;\n"
+ " uint64_clock_monotonic_t timestamp_end;\n"
+ " uint64_t content_size;\n"
+ " uint64_t packet_size;\n"
+ " unsigned long events_discarded;\n"
+ " uint32_t cpu_id;\n"
+ "};\n"
+ "\n"
+ "struct event_header_compact {\n"
+ " enum : uint5_t { compact = 0 ... 30, extended = 31 } id;\n"
+ " variant <id> {\n"
+ " struct {\n"
+ " uint27_clock_monotonic_t timestamp;\n"
+ " } compact;\n"
+ " struct {\n"
+ " uint32_t id;\n"
+ " uint64_clock_monotonic_t timestamp;\n"
+ " } extended;\n"
+ " } v;\n"
+ "} align(8);\n"
+ "\n"
+ "struct event_header_large {\n"
+ " enum : uint16_t { compact = 0 ... 65534, extended = 65535 } id;\n"
+ " variant <id> {\n" + " struct {\n"
+ " uint32_clock_monotonic_t timestamp;\n"
+ " } compact;\n" + " struct {\n"
+ " uint32_t id;\n"
+ " uint64_clock_monotonic_t timestamp;\n"
+ " } extended;\n" + " } v;\n" + "} align(8);\n" + "\n";
private static final String ctfBody = "stream {\n"
+ " id = 0;\n"
+ " event.header := struct event_header_compact;\n"
+ " packet.context := struct packet_context;\n"
+ " event.context := struct {\n"
+ " integer { size = 64; align = 8; signed = 0; encoding = none; base = 16; } _ip;\n"
+ " };\n"
+ "};\n"
+ "\n"
+ "event {\n"
+ " name = \"ust_tests_demo3:done\";\n"
+ " id = 0;\n"
+ " stream_id = 0;\n"
+ " loglevel = 4;\n"
+ " fields := struct {\n"
+ " integer { size = 32; align = 8; signed = 1; encoding = none; base = 10; } _value;\n"
+ " };\n"
+ "};\n"
+ "\n"
+ "event {\n"
+ " name = \"ust_tests_demo:starting\";\n"
+ " id = 1;\n"
+ " stream_id = 0;\n"
+ " loglevel = 2;\n"
+ " model.emf.uri = \"http://example.com/path_to_model?q=ust_tests_demo:starting\";\n"
+ " fields := struct {\n"
+ " integer { size = 32; align = 8; signed = 1; encoding = none; base = 10; } _value;\n"
+ " };\n"
+ "};\n"
+ "\n"
+ "event {\n"
+ " name = \"ust_tests_demo:done\";\n"
+ " id = 2;\n"
+ " stream_id = 0;\n"
+ " loglevel = 2;\n"
+ " model.emf.uri = \"http://example.com/path_to_model?q=ust_tests_demo:done\";\n"
+ " fields := struct {\n"
+ " integer { size = 32; align = 8; signed = 1; encoding = none; base = 10; } _value;\n"
+ " };\n"
+ "};\n"
+ "\n"
+ "event {\n"
+ " name = \"ust_tests_demo2:loop\";\n"
+ " id = 3;\n"
+ " stream_id = 0;\n"
+ " loglevel = 4;\n"
+ " fields := struct {\n"
+ " integer { size = 32; align = 8; signed = 1; encoding = none; base = 10; } _intfield;\n"
+ " integer { size = 32; align = 8; signed = 1; encoding = none; base = 16; } _intfield2;\n"
+ " integer { size = 64; align = 8; signed = 1; encoding = none; base = 10; } _longfield;\n"
+ " integer { size = 32; align = 8; signed = 1; encoding = none; base = 10; byte_order = be; } _netintfield;\n"
+ " integer { size = 32; align = 8; signed = 1; encoding = none; base = 16; byte_order = be; } _netintfieldhex;\n"
+ " integer { size = 64; align = 8; signed = 1; encoding = none; base = 10; } _arrfield1[3];\n"
+ " integer { size = 8; align = 8; signed = 1; encoding = UTF8; base = 10; } _arrfield2[10];\n"
+ " integer { size = 64; align = 8; signed = 0; encoding = none; base = 10; } __seqfield1_length;\n"
+ " integer { size = 8; align = 8; signed = 1; encoding = none; base = 10; } _seqfield1[ __seqfield1_length ];\n"
+ " integer { size = 64; align = 8; signed = 0; encoding = none; base = 10; } __seqfield2_length;\n"
+ " integer { size = 8; align = 8; signed = 1; encoding = UTF8; base = 10; } _seqfield2[ __seqfield2_length ];\n"
+ " string _stringfield;\n"
+ " floating_point { exp_dig = 8; mant_dig = 24; align = 8; } _floatfield;\n"
+ " floating_point { exp_dig = 11; mant_dig = 53; align = 8; } _doublefield;\n"
+ " };\n"
+ "};\n"
+ "\n";
private static final String enumMd =
"typealias integer { size = 32; align = 8; signed = false; } := int;\n"
+ "typealias enum { ONE = 0, a,b,c=10, d} := useless_enum;\n"
+ "struct useless{ \n"
+ " enum : uint8_t { A=0, \"B\",} enum3;\n"
+ " useless_enum enum2;"
+ " enum { C, D, E } enum4;\n"
+ " uint16_t val;\n"
+ "} ;\n"
+ "\n"
+ "event {\n"
+ " name = \"enumEvent\";\n"
+ " id = 6;\n"
+ " stream_id = 0;\n"
+ " loglevel = 5;\n"
+ " fields := struct{\n"
+ " uint16_t _some_field;\n"
// + " useless junk;\n"
// + " bad_enum a;\n"
+ " enum {A, B, C = 3 , } _other_enum;\n"
+ " };\n"
+ "};\n"
+ "\n";
private final static String contextMD =
"event {\n" +
" name = \"someOtherEvent\";\n" +
" id = 5;\n" +
" stream_id = 0;\n" +
" loglevel = 5;\n" +
" context := struct{\n" +
" uint16_t _someContext;\n" +
" };\n" +
" fields := struct{\n" +
" uint16_t _somefield;\n" +
" };\n" +
"};\n " +
"\n";
private static final String callsiteMD =
"callsite {\n"
+ " name = \"ust_tests_demo2:loop\";\n"
+ " func = \"main\";\n" + " ip = 0x400a29;\n"
+ " file = \"demo.c\";\n" + " line = 59;\n" + "};\n" + "\n"
+ "callsite {\n" + " name = \"ust_tests_demo3:done\";\n"
+ " func = \"main\";\n" + " ip = 0x400a6c;\n"
+ " file = \"demo.c\";\n" + " line = 62;\n" + "};\n" + "\n"
+ "callsite {\n" + " name = \"ust_tests_demo:done\";\n"
+ " func = \"main\";\n" + " ip = 0x400aaf;\n"
+ " file = \"demo.c\";\n" + " line = 61;\n" + "};\n" + "\n"
+ "callsite {\n" + " name = \"ust_tests_demo:starting\";\n"
+ " func = \"main\";\n" + " ip = 0x400af2;\n"
+ " file = \"demo.c\";\n" + " line = 55;\n" + "};\n";
private static final String simpleTSDL = metadataDecs + ctfStart + ctfHeaders
+ ctfBody;
private static final String enumTSDL = metadataDecs + ctfStart + ctfHeaders
+ ctfBody + enumMd;
private static final String clockTSDL = metadataDecs + clockMD + ctfStart
+ ctfHeaders + ctfBody;
private static final String envTSDL = metadataDecs + environmentMD + ctfStart
+ ctfHeaders + ctfBody;
private static final String contextTSDL = metadataDecs + environmentMD + ctfStart
+ ctfHeaders + ctfBody + contextMD;
private static final String callsiteTSDL = metadataDecs + ctfStart + ctfHeaders
+ ctfBody + callsiteMD;
private static final String allDressedTSDL = metadataDecs + environmentMD + clockMD
+ ctfStart + ctfHeaders + ctfBody + enumMd + callsiteMD;
static final String tempTraceDir = CtfCoreTestPlugin.getTemporaryDirPath()
+ File.separator + "tempTrace";
private static final int DATA_SIZE = 4096;
private static final int HEADER_SIZE = 68;
private static final int PACKET_SIZE = DATA_SIZE + HEADER_SIZE + 512;
private CTFTrace trace;
private static class Event {
private static final int EVENT_SIZE = 16;
private int eventId;
private int eventTimestamp;
private int eventContent;
public Event(int id, int content) {
eventId = id;
eventTimestamp = 0;
eventContent = content;
}
public void setEventTimestamp(int eventTimestamp) {
this.eventTimestamp = eventTimestamp;
}
public void setEventContent(int eventContent) {
this.eventContent = eventContent;
}
public void writeEvent(ByteBuffer data) {
// Id and Timestamp
int timeId = eventTimestamp << 5;
timeId |= eventId & 0x1f;
data.putInt(timeId);
// Context
long ip = 0x0000facedecafe00L + ((data.position() /
getSize()) & 0x0F);
data.putLong(ip);
// Content
data.putInt(eventContent);
}
public int getSize() {
return EVENT_SIZE;
}
}
private static void deltree(File f) {
for (File elem : f.listFiles()) {
if (elem.isDirectory()) {
deltree(elem);
}
elem.delete();
}
f.delete();
}
private static void createDummyTrace(String metadata) {
File dir = new File(tempTraceDir);
if (dir.exists()) {
deltree(dir);
}
dir.mkdirs();
File metadataFile = new File(tempTraceDir + "/metadata");
try (FileWriter fw = new FileWriter(metadataFile);) {
fw.write(metadata);
} catch (IOException e) {
e.printStackTrace();
}
byte magicLE[] = { (byte) 0xC1, (byte) 0x1F, (byte) 0xFC,
(byte) 0xC1 };
byte uuid[] = { (byte) 0xb0, 0x4d, 0x39, 0x1b, (byte) 0xe7,
0x36, 0x44, (byte) 0xc1, (byte) 0x8d, (byte) 0x89, 0x4b,
(byte) 0xb4, 0x38, (byte) 0x85, 0x7f, (byte) 0x8d };
Event ev = new Event(2, 2);
final int nbEvents = (DATA_SIZE / ev.getSize()) - 1;
final int contentSize = (nbEvents * ev.getSize() +
HEADER_SIZE) * 8;
ByteBuffer data = ByteBuffer.allocate(PACKET_SIZE);
data.order(ByteOrder.LITTLE_ENDIAN);
data.clear();
// packet header
// magic number 4
data.put(magicLE);
// uuid 16
data.put(uuid);
// stream ID 4
data.putInt(0);
// packet context
// timestamp_begin 8
data.putLong(0xa500);
// timestamp_end 8
data.putLong(nbEvents * 0x10000 + 0xa5a6);
// content_size 8
data.putLong(contentSize);
// packet_size 8
data.putLong(PACKET_SIZE * 8);
// events_discarded 8
data.putLong(0);
// cpu_id 4
data.putInt(0);
// fill me
for (int i = 0; i < nbEvents; i++) {
ev.setEventTimestamp(i * 0x10000 + 0xa5a5);
ev.setEventContent(i);
ev.writeEvent(data);
}
// The byteBuffer needs to be flipped in file writing mode
data.flip();
File dummyFile = new File(tempTraceDir + "/dummyChan");
try (FileOutputStream fos = new FileOutputStream(dummyFile);) {
fos.getChannel().write(data);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Simple test (only the minimum)
*
* @throws CTFException
* something wrong happened
*/
@Test
public void TSDLSimpleTest() throws CTFException {
createDummyTrace(simpleTSDL);
trace = new CTFTrace(tempTraceDir);
assertNotNull(trace);
}
/**
* Test with environment variables
*
* @throws CTFException
* something wrong happened
*/
@Test
public void TSDLEnvironmentTest() throws CTFException {
createDummyTrace(envTSDL);
trace = new CTFTrace(tempTraceDir);
assertNotNull(trace);
}
/**
* Test with Clocks
*
* @throws CTFException
* something wrong happened
*/
@Test
public void TSDLEnumTest() throws CTFException {
createDummyTrace(enumTSDL);
trace = new CTFTrace(tempTraceDir);
assertNotNull(trace);
}
/**
* Test with Clocks
*
* @throws CTFException
* something wrong happened
*/
@Test
public void TSDLClockTest() throws CTFException {
createDummyTrace(clockTSDL);
trace = new CTFTrace(tempTraceDir);
assertNotNull(trace);
}
/**
* Test with Contexts
*
* @throws CTFException
* something wrong happened
*/
@Test
public void TSDLContextTest() throws CTFException {
createDummyTrace(contextTSDL);
trace = new CTFTrace(tempTraceDir);
assertNotNull(trace);
}
/**
* Test with Callsites
*
* @throws CTFException
* something wrong happened
*/
@Test
public void TSDLCallsiteTest() throws CTFException {
createDummyTrace(callsiteTSDL);
trace = new CTFTrace(tempTraceDir);
assertNotNull(trace);
}
/**
* Test everything
*
* @throws CTFException
* something wrong happened
*/
@Test
public void TSDLAllTest() throws CTFException {
createDummyTrace(allDressedTSDL);
trace = new CTFTrace(tempTraceDir);
assertNotNull(trace);
final List<IEventDeclaration> eventDeclarations = new ArrayList<>(trace.getEventDeclarations(0L));
final EventDeclaration eventDeclaration = (EventDeclaration) eventDeclarations.get(2);
assertEquals("http://example.com/path_to_model?q=ust_tests_demo:done",
eventDeclaration.getCustomAttribute("model.emf.uri"));
}
}