diff --git a/java_console/models/src/com/rusefi/tracing/Entry.java b/java_console/models/src/com/rusefi/tracing/Entry.java index 0fd9dedc01..37956ad70d 100644 --- a/java_console/models/src/com/rusefi/tracing/Entry.java +++ b/java_console/models/src/com/rusefi/tracing/Entry.java @@ -1,9 +1,16 @@ package com.rusefi.tracing; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + public class Entry { private final String name; private final Phase phase; - private final double timestampSeconds; + private double timestampSeconds; public Entry(String name, Phase phase, double timestampSeconds) { this.name = name; @@ -33,6 +40,52 @@ public class Entry { sb.append(y); } + public static int readInt(DataInputStream in) throws IOException { + int ch1 = in.read(); + int ch2 = in.read(); + int ch3 = in.read(); + int ch4 = in.read(); + if ((ch1 | ch2 | ch3 | ch4) < 0) + throw new EOFException(); + return ((ch4 << 24) + (ch3 << 16) + (ch2 << 8) + (ch1 << 0)); + } + + + public static List parseBuffer(byte[] packet) { + List result = new ArrayList<>(); + double minValue = Double.MAX_VALUE; + try { + DataInputStream is = new DataInputStream(new ByteArrayInputStream(packet)); + is.readByte(); // skip TS result code + for (int i = 0; i < packet.length - 1; i += 8) { + byte type = is.readByte(); + byte phase = is.readByte(); + byte data = is.readByte(); + byte thread = is.readByte(); + + int timestampNt = readInt(is); + + + double timestampSeconds = timestampNt / 1000000.0; + minValue = Math.min(minValue, timestampNt); + Entry e = new Entry("t" + type, Phase.decode(phase), timestampSeconds); + result.add(e); + } + + for (Entry e : result) + e.adjustTimestamp(minValue); + + + } catch (IOException e) { + throw new IllegalStateException(e); + } + return result; + } + + private void adjustTimestamp(double minValue) { + timestampSeconds -= minValue; + } + @Override public String toString() { StringBuilder sb = new StringBuilder(); diff --git a/java_console/models/src/com/rusefi/tracing/JsonOutput.java b/java_console/models/src/com/rusefi/tracing/JsonOutput.java index 96931b73d7..15d8ac8e5f 100644 --- a/java_console/models/src/com/rusefi/tracing/JsonOutput.java +++ b/java_console/models/src/com/rusefi/tracing/JsonOutput.java @@ -22,7 +22,7 @@ public class JsonOutput { writeToStream(testEntries, new FileOutputStream("hello_trace.json")); } - private static void writeToStream(List testEntries, OutputStream outputStream) throws IOException { + public static void writeToStream(List testEntries, OutputStream outputStream) throws IOException { Writer out = new OutputStreamWriter(outputStream); out.write("{\"traceEvents\": [\n"); diff --git a/java_console/models/src/com/rusefi/tracing/Phase.java b/java_console/models/src/com/rusefi/tracing/Phase.java index c1185d798f..e98febf992 100644 --- a/java_console/models/src/com/rusefi/tracing/Phase.java +++ b/java_console/models/src/com/rusefi/tracing/Phase.java @@ -6,4 +6,19 @@ public enum Phase { // End E, i, + ; + + public static Phase decode(byte phase) { + switch (phase) { + case 0: + return B; + case 1: + return E; + case 2: + case 3: + return i; + default: + throw new IllegalStateException("Unexpected " + phase); + } + } } diff --git a/java_console/ui/src/com/rusefi/BenchTestPane.java b/java_console/ui/src/com/rusefi/BenchTestPane.java index 66180e53d1..df3eb095d0 100644 --- a/java_console/ui/src/com/rusefi/BenchTestPane.java +++ b/java_console/ui/src/com/rusefi/BenchTestPane.java @@ -1,13 +1,25 @@ package com.rusefi; +import com.rusefi.binaryprotocol.BinaryProtocol; +import com.rusefi.binaryprotocol.BinaryProtocolHolder; import com.rusefi.config.generated.Fields; +import com.rusefi.tracing.Entry; +import com.rusefi.tracing.JsonOutput; import com.rusefi.ui.MessagesView; +import com.rusefi.ui.util.UiUtils; import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.List; import static com.rusefi.CommandControl.TEST; +import static com.rusefi.binaryprotocol.BinaryProtocolCommands.RESPONSE_OK; +import static com.rusefi.binaryprotocol.IoHelper.checkResponseCode; public class BenchTestPane { private final JPanel content = new JPanel(new GridLayout(2, 5)); @@ -15,6 +27,7 @@ public class BenchTestPane { public BenchTestPane() { content.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + content.add(grabPerformanceTrace()); content.add(createFanTest()); content.add(createAcRelayTest()); content.add(createFuelPumpTest()); @@ -38,6 +51,31 @@ public class BenchTestPane { content.add(new MessagesView().messagesScroll); } + private Component grabPerformanceTrace() { + JButton button = new JButton("Grab PTrace"); + button.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + BinaryProtocol bp = BinaryProtocolHolder.INSTANCE.get(); + bp.executeCommand(new byte[]{'r'}, "begin trace", false); + + try { + Thread.sleep(500); + + byte[] packet = bp.executeCommand(new byte[]{'b'}, "get trace", true); + if (!checkResponseCode(packet, RESPONSE_OK) || ((packet.length - 1) % 8) != 0) + throw new IllegalStateException("Unexpected packet"); + + List data = Entry.parseBuffer(packet); + JsonOutput.writeToStream(data, new FileOutputStream("hello_trace.json")); + } catch (IOException | InterruptedException e1) { + throw new IllegalStateException(e1); + } + } + }); + return UiUtils.wrap(button); + } + private Component createMILTest() { CommandControl panel = new CommandControl("MIL", "check_engine.jpg", TEST) { @NotNull