Full Code of penberg/falcon for AI

master 5ee923330896 cached
24 files
30.2 KB
8.7k tokens
62 symbols
1 requests
Download .txt
Repository: penberg/falcon
Branch: master
Commit: 5ee923330896
Files: 24
Total size: 30.2 KB

Directory structure:
gitextract__2rp4aw1/

├── .gitignore
├── LICENSE
├── README.md
├── falcon/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── falcon/
│       │           └── fix/
│       │               ├── ByteString.java
│       │               ├── Field.java
│       │               ├── Message.java
│       │               ├── MessageType.java
│       │               ├── MessageTypes.java
│       │               ├── ParseException.java
│       │               ├── ParseFailedException.java
│       │               ├── PartialParseException.java
│       │               ├── Protocol.java
│       │               ├── Session.java
│       │               ├── Tags.java
│       │               ├── Version.java
│       │               ├── Versions.java
│       │               └── package-info.java
│       └── test/
│           └── java/
│               └── falcon/
│                   └── fix/
│                       ├── MemoryMeterTest.java
│                       └── ProtocolTest.java
├── falcon-perf-test/
│   ├── bin/
│   │   └── falcon-perf-test
│   ├── pom.xml
│   └── src/
│       └── main/
│           └── java/
│               └── falcon/
│                   └── fix/
│                       └── perf/
│                           └── ClientPerfTest.java
└── pom.xml

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
target


================================================
FILE: LICENSE
================================================
Copyright (C) 2013 Pekka Enberg

Falcon is distributed under the 2-clause BSD license:

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


================================================
FILE: README.md
================================================
# Falcon

Falcon is a high performance, low latency FIX engine for the JVM. It provides
an API that enables FIX connectivity for both buy side and sell side
applications such as trading systems and order management systems.

The engine is designed to avoid heap allocations on the TX and RX paths to
avoid GC pauses that are disastrous for low-latency applications. The engine
is packed with other optimizations such as avoiding querying the system clock
for every message and open-coding formatting and parsing functions where the
JRE allocates memory implicitly.

Falcon is able to achieve 8 µs RTT on when running the latency tester client
and server on the same machine.

## Features

* Zero-copy, non-blocking, low-latency NIO networking
* Low heap allocation rate in the FIX engine core
* Small memory footprint for session and message data structures

## Example

An example application that sends 100000 ``NewOrderSingle`` messages looks like
this:

```java
import static java.net.StandardSocketOptions.*;
import java.nio.channels.*;
import java.net.*;
import java.nio.*;

import static falcon.fix.MessageTypes.*;
import static falcon.fix.Versions.*;
import static falcon.fix.Tags.*;
import falcon.fix.*;

public class Example {
  public static void main(String[] args) throws Exception {
    SocketChannel socket = connect("localhost", 7070);

    Session session = new Session(socket, FIX_4_2, "HERMES", "INET");

    session.updateTime();

    session.send(new Message.Builder(Logon)
        .add(new Field(EncryptMethod, "0" ))
        .add(new Field(HeartBtInt,    "30"))
        .build());

    Message newOrder =
      new Message.Builder(NewOrderSingle)
          .add(new Field(EncryptMethod, "0" ))
          .add(new Field(HeartBtInt,    "30"))
          .build();

    for (int i = 0; i < 100000; i++) {
      if ((i % 10000) == 0) {
        session.updateTime();
      }
      session.send(newOrder);
    }

    session.updateTime();

    session.send(new Message.Builder(Logout).build());

    socket.close();
  }

  private static SocketChannel connect(String host, int port) throws Exception {
    InetSocketAddress addr = new InetSocketAddress(host, port);
    SocketChannel socket = SocketChannel.open();
    socket.configureBlocking(false);
    socket.setOption(TCP_NODELAY, true);
    socket.connect(addr);
    socket.finishConnect();
    return socket;
  }
}
```

## Performance

The FIX engine has been measured to have 8 µs RTT for a loopback ping-pong test
where client sends a ``NewOrderSingle`` message and waits for an
``ExecutionReport`` message to arrive. The numbers include the time spent in
Linux TCP/IP stack and the loopback device.

To reproduce the results, first download and build [Libtrading]. Then start the
FIX performance test server:

```
$ taskset -c 0 tools/fix/fix_server -m 1 -p 7070
```

Finally, run the Falcon latency tests:

```
$ ./falcon-perf-test/bin/falcon-perf-test 1000000
87693.5 messages/second
min/avg/max = 9.8/11.4/19935.3 µs
Percentiles:
  1.00%: 10.15 µs
  5.00%: 10.51 µs
 10.00%: 10.61 µs
 50.00%: 11.12 µs
 90.00%: 11.90 µs
 95.00%: 13.27 µs
 99.00%: 14.53 µs
```

  [Libtrading]: https://github.com/libtrading/libtrading

## License

Copyright © 2013-2015 Pekka Enberg and contributors

Falcon is distributed under the 2-clause BSD license.


================================================
FILE: falcon/pom.xml
================================================
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>falcon</groupId>
    <artifactId>falcon-parent</artifactId>
    <version>0.1.0-master-SNAPSHOT</version>
  </parent>

  <groupId>falcon</groupId>
  <artifactId>falcon</artifactId>
  <name>Falcon</name>

  <dependencies>
    <dependency>
      <groupId>com.github.stephenc</groupId>
      <artifactId>jamm</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
          <execution>
            <id>copy-dependencies</id>
            <phase>generate-test-resources</phase>
            <goals>
              <goal>copy</goal>
            </goals>
            <configuration>
              <artifactItems>
                <artifactItem>
                  <groupId>com.github.stephenc</groupId>
                  <artifactId>jamm</artifactId>
                  <type>jar</type>
                  <outputDirectory>${project.build.directory}</outputDirectory>
                  <destFileName>jamm.jar</destFileName>
                </artifactItem>
              </artifactItems>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <argLine>-javaagent:${project.build.directory}/jamm.jar</argLine>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>


================================================
FILE: falcon/src/main/java/falcon/fix/ByteString.java
================================================
package falcon.fix;

import java.nio.ByteBuffer;

public final class ByteString {
  final byte[] data;

  /**
   * Returns a new byte string that contains a copy of <code>len</code> bytes from <code>buf</code>.
   */
  public static ByteString of(ByteBuffer buf, int len) {
    byte[] data = new byte[len];
    buf.get(data);
    return new ByteString(data);
  }

  public ByteString(byte[] data) {
    this.data = data;
  }
}


================================================
FILE: falcon/src/main/java/falcon/fix/Field.java
================================================
package falcon.fix;

import java.nio.ByteBuffer;

/**
 * A field is composed of a tag and value pair.
 */
public class Field {

  private int tag;
  private Object value;

  public Field(int tag, Object value) {
    this.tag   = tag;
    this.value = value;
  }

  public int tag() {
    return tag;
  }

  public Object value() {
    return value;
  }
}


================================================
FILE: falcon/src/main/java/falcon/fix/Message.java
================================================
package falcon.fix;

import static falcon.fix.Tags.*;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

/**
 * A message is composed of number of fields, grouped in a header, body, and a
 * trailer.
 */
public class Message {

  private List<Field>  fields;
  private MessageType  type;

  /**
   * Constructs a message of specified type and fields.
   *
   * @param type   Type of this message.
   * @param fields Fields for this message.
   *
   * The constructed message has a header and a trailer, and the specified fields.
   */
  public Message(MessageType type, List<Field> fields) {
    this.type   = type;
    this.fields = fields;
  }

  public MessageType type() {
    return type;
  }

  public List<Field> fields() {
    return fields;
  }

  /**
   * Message builder.
   */
  public static class Builder {
    private List<Field>  fields = new ArrayList<>();
    private MessageType type;

    public Builder(MessageType type) {
      this.type = type;
    }

    public Builder add(Field field) {
      fields.add(field);
      return this;
    }

    public Message build() {
      return new Message(type, fields);
    }
  }
}


================================================
FILE: falcon/src/main/java/falcon/fix/MessageType.java
================================================
package falcon.fix;

/**
 * A message type specifies which fields a message contains.
 */
public class MessageType {

  private String value;

  public MessageType(String value) {
    this.value = value;
  }

  public String value() {
    return value;
  }
}


================================================
FILE: falcon/src/main/java/falcon/fix/MessageTypes.java
================================================
package falcon.fix;

public class MessageTypes {

  public static final MessageType Heartbeat      = new MessageType("0");
  public static final MessageType TestRequest    = new MessageType("1");
  public static final MessageType ResendRequest  = new MessageType("2");
  public static final MessageType Reject         = new MessageType("3");
  public static final MessageType SequenceReset  = new MessageType("4");
  public static final MessageType Logout         = new MessageType("5");
  public static final MessageType ExecutionReport= new MessageType("8");
  public static final MessageType Logon          = new MessageType("A");
  public static final MessageType NewOrderSingle = new MessageType("D");

}


================================================
FILE: falcon/src/main/java/falcon/fix/ParseException.java
================================================
package falcon.fix;

public class ParseException extends Exception {
  public ParseException() {
  }

  public ParseException(String message) {
    super(message);
  }
}


================================================
FILE: falcon/src/main/java/falcon/fix/ParseFailedException.java
================================================
package falcon.fix;

public class ParseFailedException extends ParseException {
  public ParseFailedException(String message) {
    super(message);
  }
}


================================================
FILE: falcon/src/main/java/falcon/fix/PartialParseException.java
================================================
package falcon.fix;

public class PartialParseException extends ParseException {
}


================================================
FILE: falcon/src/main/java/falcon/fix/Protocol.java
================================================
package falcon.fix;

import static falcon.fix.MessageTypes.*;

import java.nio.ByteBuffer;

/**
 * On-wire protocol parsing and formatting.
 */
public class Protocol {

  /*
   * Maximum message header size in bytes.
   */
  public static final int MAX_HEADER_SIZE = 64;

  /*
   * Maximum message body size in bytes.
   */
  public static final int MAX_BODY_SIZE = 4096;

  /**
   * Format field to on-wire format.
   */
  public static void format(ByteBuffer buf, int tag, byte[] value) {
    writeInt(buf, tag);
    buf.put((byte) '=');
    buf.put(value);
    buf.put((byte) 0x01);
  }

  /**
   * Format field to on-wire format.
   */
  public static void formatInt(ByteBuffer buf, int tag, int value) {
    writeInt(buf, tag);
    buf.put((byte) '=');
    writeInt(buf, value);
    buf.put((byte) 0x01);
  }

  public static void formatString(ByteBuffer buf, int tag, String value) {
    writeInt(buf, tag);
    buf.put((byte) '=');
    for (int i = 0; i < value.length(); i++) {
      buf.put((byte) value.charAt(i));
    }
    buf.put((byte) 0x01);
  }

  public static void formatCheckSum(ByteBuffer buf, int tag, int value) {
    writeInt(buf, tag);
    buf.put((byte) '=');
    if (value < 10) {
      buf.put((byte) '0');
    }
    if (value < 100) {
      buf.put((byte) '0');
    }
    writeInt(buf, value);
    buf.put((byte) 0x01);
  }

  public static void writeInt(ByteBuffer buf, int n) {
    if (n < 0) {
      buf.put((byte) '-');
    }
    n = Math.abs(n);
    int start = buf.position();
    do {
      buf.put((byte)('0' + n % 10));
      n /= 10;
    } while (n > 0);
    int end = buf.position();
    int i = start;
    int j = end - 1;
    while (i < j) {
      byte tmp = buf.get(i);
      buf.put(i, buf.get(j));
      buf.put(j, tmp);
      i++; j--;
    }
  }

  public static void match(ByteBuffer buf, int tag) throws ParseException {
    matchTag(buf, tag);
    while (buf.get() != (byte)0x01)
      ;;
  }

  public static int matchInt(ByteBuffer buf, int tag) throws ParseException {
    matchTag(buf, tag);
    return parseInt(buf, (byte)0x01);
  }

  public static int parseInt(ByteBuffer buf, byte delimiter) {
    int sign = 1;
    if (buf.get(buf.position()) == (byte)'-') {
      buf.get();
      sign = -1;
    }
    int result = 0;
    for (;;) {
      byte ch = buf.get();
      if (ch == delimiter) {
        break;
      }
      result *= 10;
      result += (byte)ch - (byte)'0';
    }
    return sign * result;
  }

  public static ByteString parseString(ByteBuffer buf, byte delimiter) {
    int start = buf.position();
    for (;;) {
      byte ch = buf.get();
      if (ch == delimiter) {
        break;
      }
    }
    int end = buf.position() - 1;
    buf.position(start);
    return ByteString.of(buf, end-start);
  }

  public static MessageType matchMsgType(ByteBuffer buf) throws ParseException {
    matchTag(buf, Tags.MsgType);
    MessageType result = null;
    switch (buf.get()) {
    case (byte)'0': result = Heartbeat;       break;
    case (byte)'1': result = TestRequest;     break;
    case (byte)'2': result = ResendRequest;   break;
    case (byte)'3': result = Reject;          break;
    case (byte)'4': result = SequenceReset;   break;
    case (byte)'5': result = Logout;          break;
    case (byte)'8': result = ExecutionReport; break;
    case (byte)'A': result = Logon;           break;
    case (byte)'D': result = NewOrderSingle;  break;
    case (byte)0x01:
      throw new ParseFailedException("Invalid MsgType (35)");
    default:
      throw new ParseFailedException("Tag specified without a value");
    }
    if (buf.get() != (byte)0x01) {
      throw new ParseFailedException("Invalid MsgType (35)");
    }
    return result;
  }

  public static void matchTag(ByteBuffer buf, int tag) throws ParseException {
    int actual = parseInt(buf, (byte)'=');
    if (actual != tag) {
      throw new ParseFailedException("Required tag missing");
    }
  }
}


================================================
FILE: falcon/src/main/java/falcon/fix/Session.java
================================================
package falcon.fix;

import static falcon.fix.Tags.*;
import java.nio.channels.*;
import java.text.*;
import java.util.*;
import java.nio.*;

/**
 * A session is bi-directional stream of messages between two parties where
 * message ordering is guaranteed with monotonically increasing message
 * sequence numbers.
 */
public class Session {

  private ByteBuffer headBuf = ByteBuffer.allocate(Protocol.MAX_HEADER_SIZE);
  private ByteBuffer bodyBuf = ByteBuffer.allocate(Protocol.MAX_BODY_SIZE);
  private ByteBuffer rxBuf = ByteBuffer.allocate(Protocol.MAX_HEADER_SIZE + Protocol.MAX_BODY_SIZE);

  private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd-HH:mm:ss.SSS");
  private SocketChannel socket;
  private String senderCompId;
  private String targetCompId;
  private Version version;
  private int sequence;
  private String now;

  public Session(SocketChannel socket, Version version, String senderCompId, String targetCompId) {
    this.socket       = socket;
    this.version      = version;
    this.senderCompId = senderCompId;
    this.targetCompId = targetCompId;
  }

  public void updateTime() {
    now = dateFormat.format(new Date());
  }

  public void send(Message msg) throws Exception {
    Protocol.formatString(bodyBuf, MsgType, msg.type().value());
    Protocol.formatString(bodyBuf, SenderCompID, senderCompId);
    Protocol.formatString(bodyBuf, TargetCompID, targetCompId);
    Protocol.formatInt(bodyBuf, MsgSeqNum, sequence++);
    Protocol.formatString(bodyBuf, SendingTime, now);

    List<Field> fields = msg.fields();
    for (int i = 0; i < fields.size(); i++) {
      Field field = fields.get(i);
      Object value = field.value();
      if (value instanceof String) {
        Protocol.formatString(bodyBuf, field.tag(), (String) field.value());
      } else if (value instanceof Integer) {
        Protocol.formatInt(bodyBuf, field.tag(), ((Integer) field.value()).intValue());
      } else {
        throw new IllegalStateException();
      }
    }

    Protocol.format(headBuf, BeginString, version.value());
    Protocol.formatInt(headBuf, BodyLength, bodyBuf.position());

    Protocol.formatCheckSum(bodyBuf, CheckSum, (sum(headBuf) + sum(bodyBuf)) % 256);

    headBuf.flip();
    bodyBuf.flip();

    while (headBuf.remaining() > 0) {
      socket.write(headBuf);
    }
    while (bodyBuf.remaining() > 0) {
      socket.write(bodyBuf);
    }

    headBuf.clear();
    bodyBuf.clear();
  }

  public Message recv() throws Exception {
    int count = socket.read(rxBuf);
    if (count <= 0) {
      return null;
    }
    rxBuf.flip();
    rxBuf.mark();
    List<Field> fields = new ArrayList<Field>();
    MessageType msgType = null;
    try {
      Protocol.match(rxBuf, BeginString);
      int bodyLen = Protocol.matchInt(rxBuf, BodyLength);
      int msgTypeOffset = rxBuf.position();
      msgType = Protocol.matchMsgType(rxBuf);
      int checksumOffset = msgTypeOffset + bodyLen;
      rxBuf.position(checksumOffset);
      int checksumActual = sum(rxBuf) % 256;
      int checksumExpected = Protocol.matchInt(rxBuf, CheckSum);
      if (checksumExpected != checksumActual) {
        throw new RuntimeException(String.format("Invalid checksum: expected %d, got: %d", checksumExpected, checksumActual));
      }
      int endOffset = rxBuf.position();
      rxBuf.position(msgTypeOffset);
      while (rxBuf.position() < checksumOffset) {
        int tag = Protocol.parseInt(rxBuf, (byte)'=');
        ByteString value = Protocol.parseString(rxBuf, (byte)0x01);
        fields.add(new Field(tag, value));
      }
      rxBuf.position(endOffset);
    } catch (PartialParseException e) {
      rxBuf.reset();
      return null;
    } catch (ParseFailedException e) {
      throw new RuntimeException("Garbled message", e);
    }
    rxBuf.compact();
    return new Message(msgType, fields);
  }

  private static int sum(ByteBuffer buf) {
    return sum(buf, 0, buf.position());
  }

  private static int sum(ByteBuffer buf, int start, int end) {
    int result = 0;
    for (int i = start; i < end; i++)
      result += buf.get(i);
    return result;
  }
}


================================================
FILE: falcon/src/main/java/falcon/fix/Tags.java
================================================
package falcon.fix;

public class Tags {

  public static final int BeginString   = 8;
  public static final int BodyLength    = 9;
  public static final int CheckSum      = 10;
  public static final int MsgSeqNum     = 34;
  public static final int MsgType       = 35;
  public static final int SenderCompID  = 49;
  public static final int SendingTime   = 52;
  public static final int TargetCompID  = 56;
  public static final int EncryptMethod = 98;
  public static final int HeartBtInt    = 108;
}


================================================
FILE: falcon/src/main/java/falcon/fix/Version.java
================================================
package falcon.fix;

/**
 * A version specifies which base standard is followed in a session.
 *
 * Session version is specified in the <b>BeginString</b> tag in message
 * header. Although not supported by the standard, many dialects are a
 * combination of two or more versions. <b>BeginString</b> thus only represents
 * the base specification and message types and tags are typically specified in
 * proprietary trading venue specifications. Session level semantics usually
 * follow the specified base standard, but not always.
 */
public class Version {

  private byte[] value;

  public Version(String value) {
    this(value.getBytes());
  }

  public Version(byte[] value) {
    this.value = value;
  }

  public byte[] value() {
    return value;
  }
}


================================================
FILE: falcon/src/main/java/falcon/fix/Versions.java
================================================
package falcon.fix;

public class Versions {

  /**
   * FIX 4.1 based sessions.
   */
  public static Version FIX_4_1 = new Version("FIX.4.1");

  /**
   * FIX 4.2 based sessions.
   */
  public static Version FIX_4_2 = new Version("FIX.4.2");

  /**
   * FIX 4.3 based sessions.
   */
  public static Version FIX_4_3 = new Version("FIX.4.3");

  /**
   * FIX 4.4 based sessions.
   */
  public static Version FIX_4_4 = new Version("FIX.4.4");
}


================================================
FILE: falcon/src/main/java/falcon/fix/package-info.java
================================================
/**
 * Falcon FIX core classes.
 */
package falcon.fix;


================================================
FILE: falcon/src/test/java/falcon/fix/MemoryMeterTest.java
================================================
package falcon.fix;

import static falcon.fix.MessageTypes.*;
import static falcon.fix.Versions.*;
import static falcon.fix.Tags.*;

import org.github.jamm.MemoryMeter;
import java.nio.channels.*;
import org.junit.Test;

public class MemoryMeterTest {

  private MemoryMeter meter = new MemoryMeter();

  @Test
  public void footprint() throws Exception {
    Session session = new Session(SocketChannel.open(), FIX_4_2, "HERMES", "INET");
    measure(session);

    Message msg =
      new Message.Builder(Logon)
        .add(new Field(EncryptMethod, "0" ))
        .add(new Field(HeartBtInt,    "30"))
        .build();
    measure(msg);

    Field field = new Field(EncryptMethod, "0" );
    measure(field);
  }

  private void measure(Object obj) {
    System.out.printf("Memory footprint of '%s':\n\n", obj.getClass().getName());
    System.out.printf("  Size (shallow): %d bytes\n", meter.measure(obj));
    System.out.printf("  Size (deep)   : %d bytes\n", meter.measureDeep(obj));
    System.out.printf("  Child objects : %d\n", meter.countChildren(obj));
    System.out.printf("\n");
  }
}


================================================
FILE: falcon/src/test/java/falcon/fix/ProtocolTest.java
================================================
package falcon.fix;

import static org.junit.Assert.*;
import java.nio.charset.*;
import org.junit.Test;
import java.nio.*;

public class ProtocolTest {
  @Test
  public void writeInt() throws Exception {
    assertEquals("-123", writeInt(-123));
    assertEquals(   "0", writeInt(0));
    assertEquals( "123", writeInt(123));
  }

  private static String writeInt(int n) throws Exception {
    ByteBuffer buf = ByteBuffer.allocate(128);
    Protocol.writeInt(buf, n);
    buf.flip();
    byte[] bytes = new byte[buf.remaining()];
    buf.get(bytes);
    return new String(bytes, "ASCII");
  }

  @Test
  public void parseInt() throws Exception {
    assertEquals(-123, parseInt("-123\1"));
    assertEquals(   0, parseInt("0\1"));
    assertEquals( 123, parseInt("123\1"));
  }

  private static int parseInt(String s) throws Exception {
    Charset charset = Charset.forName("UTF-8");
    CharsetEncoder encoder = charset.newEncoder();
    ByteBuffer buf = encoder.encode(CharBuffer.wrap(s));
    return Protocol.parseInt(buf, (byte)0x01);
  }
}


================================================
FILE: falcon-perf-test/bin/falcon-perf-test
================================================
#!/bin/sh

if [ -z "$JAVACMD" ] ; then
  if [ -z "$JAVA_HOME" ] ; then
    JAVACMD='java'
  else
    JAVACMD="$JAVA_HOME/bin/java"
  fi
fi

java_class=falcon.fix.perf.ClientPerfTest

JAVA_OPTS="-verbose:gc -cp falcon-perf-test/target/falcon-perf-test-0.1.0-master-SNAPSHOT-jar-with-dependencies.jar"

$JAVACMD $JAVA_OPTS $java_class $@


================================================
FILE: falcon-perf-test/pom.xml
================================================
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>falcon</groupId>
    <artifactId>falcon-parent</artifactId>
    <version>0.1.0-master-SNAPSHOT</version>
  </parent>

  <groupId>falcon</groupId>
  <artifactId>falcon-perf-test</artifactId>
  <name>Falcon Performance Test</name>

  <dependencies>
    <dependency>
      <groupId>falcon</groupId>
      <artifactId>falcon</artifactId>
      <version>${project.version}</version>
    </dependency>
    <dependency>
      <groupId>org.hdrhistogram</groupId>
      <artifactId>HdrHistogram</artifactId>
      <version>2.1.4</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
          <archive>
            <manifest>
              <mainClass>falcon.fix.perf.ClientPerfTest</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <executions>
          <execution>
            <id>falcon-jar</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
            <configuration>
              <descriptorRefs>
                <descriptorRef>jar-with-dependencies</descriptorRef>
              </descriptorRefs>
              <archive>
                <manifest>
                  <mainClass>falcon.fix.perf.ClientPerfTest</mainClass>
                </manifest>
              </archive>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>


================================================
FILE: falcon-perf-test/src/main/java/falcon/fix/perf/ClientPerfTest.java
================================================
package falcon.fix.perf;

import static java.net.StandardSocketOptions.TCP_NODELAY;
import static falcon.fix.MessageTypes.*;
import static falcon.fix.Versions.*;
import org.HdrHistogram.Histogram;
import static falcon.fix.Tags.*;
import java.nio.channels.*;
import java.net.*;
import java.nio.*;

import falcon.fix.*;

public class ClientPerfTest {
  public static void main(String[] args) throws Exception {
    if (args.length != 1)  {
        System.out.printf("  usage: %s <iterations>\n", ClientPerfTest.class.getSimpleName());
        System.exit(1);
    }

    int iterations = Integer.parseInt(args[0]);

    SocketChannel socket = connect("localhost", 7070);

    Session session = new Session(socket, FIX_4_2, "HERMES", "INET");

    session.updateTime();

    session.send(new Message.Builder(Logon)
        .add(new Field(EncryptMethod, "0" ))
        .add(new Field(HeartBtInt,    "30"))
        .build());

    Message newOrder =
      new Message.Builder(NewOrderSingle)
          .add(new Field(EncryptMethod, "0" ))
          .add(new Field(HeartBtInt,    "30"))
          .build();

    long duration = 0;
    long min = Long.MAX_VALUE;
    long max = 0;

    Histogram histogram = new Histogram(3);

    for (int i = 0; i < iterations; i++) {
      long iterationStart = System.nanoTime();

      if ((i % 10000) == 0) {
        session.updateTime();
      }

      session.send(newOrder);

      for (;;) {
        Message msg = session.recv();
        if (msg != null) {
          break;
        }
      }

      long iterationEnd = System.nanoTime();

      long iterationTime = iterationEnd - iterationStart;

      duration += iterationTime;

      histogram.recordValue(iterationTime);
      min = Math.min(min, iterationTime);
      max = Math.max(max, iterationTime);
    }

    long end = System.nanoTime();

    session.updateTime();

    session.send(new Message.Builder(Logout).build());

    socket.close();

    double avg = (double)duration / (double)iterations;
    double seconds = (double)duration / 1000000000.0;
    System.out.printf("%f seconds\n", seconds);
    System.out.printf("%.1f messages/second\n", (double)iterations/seconds);
    System.out.printf("min/avg/max = %.1f/%.1f/%.1f µs\n",
      (double)min / 1000.0, (double)avg / 1000.0, (double)max / 1000.0);
    System.out.printf("Percentiles:\n");
    System.out.printf("  1.00%%: %.2f µs\n", nanosToMicros(histogram.getValueAtPercentile(  1.00)));
    System.out.printf("  5.00%%: %.2f µs\n", nanosToMicros(histogram.getValueAtPercentile(  5.00)));
    System.out.printf(" 10.00%%: %.2f µs\n", nanosToMicros(histogram.getValueAtPercentile( 10.00)));
    System.out.printf(" 50.00%%: %.2f µs\n", nanosToMicros(histogram.getValueAtPercentile( 50.00)));
    System.out.printf(" 90.00%%: %.2f µs\n", nanosToMicros(histogram.getValueAtPercentile( 90.00)));
    System.out.printf(" 95.00%%: %.2f µs\n", nanosToMicros(histogram.getValueAtPercentile( 95.00)));
    System.out.printf(" 99.00%%: %.2f µs\n", nanosToMicros(histogram.getValueAtPercentile( 99.00)));
  }

  private static SocketChannel connect(String host, int port) throws Exception {
    InetSocketAddress addr = new InetSocketAddress(host, port);
    SocketChannel socket = SocketChannel.open();
    socket.configureBlocking(false);
    socket.setOption(TCP_NODELAY, true);
    socket.connect(addr);
    while (!socket.finishConnect());
    return socket;
  }

  private static double nanosToMicros(double nano) {
    return nano / 1000.0;
  }
}


================================================
FILE: pom.xml
================================================
<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>falcon</groupId>
  <artifactId>falcon-parent</artifactId>
  <name>Falcon (parent)</name>
  <packaging>pom</packaging>
  <version>0.1.0-master-SNAPSHOT</version>

  <url>http://github.com/penberg/falcon/</url>
  <description>FIX engine for the JVM</description>

  <developers>
    <developer>
      <id>penberg</id>
      <name>Pekka Enberg</name>
      <email>penberg@iki.fi</email>
    </developer>
  </developers>

  <licenses>
    <license>
      <name>The Apache Software License, Version 2.0</name>
      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
      <distribution>repo</distribution>
    </license>
  </licenses>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <scm>
    <connection>scm:git:git@github.com:penberg/falcon.git</connection>
    <developerConnection>scm:git:git@github.com:penberg/falcon.git</developerConnection>
    <url>git@github.com:penberg/falcon.git</url>
  </scm>

  <modules>
    <module>falcon</module>
    <module>falcon-perf-test</module>
  </modules>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>com.github.stephenc</groupId>
        <artifactId>jamm</artifactId>
        <version>0.2.5</version>
      </dependency>
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.10</version>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.1</version>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-dependency-plugin</artifactId>
          <version>2.8</version>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.16</version>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-jar-plugin</artifactId>
          <version>2.4</version>
        </plugin>
        <plugin>
          <groupId>org.apache-maven-plugins</groupId>
          <artifactId>maven-assembly-plugin</artifactId>
          <version>2.4</version>
        </plugin>
      </plugins>
    </pluginManagement>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.7</source>
          <target>1.7</target>
          <encoding>${project.build.sourceEncoding}</encoding>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
Download .txt
gitextract__2rp4aw1/

├── .gitignore
├── LICENSE
├── README.md
├── falcon/
│   ├── pom.xml
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── falcon/
│       │           └── fix/
│       │               ├── ByteString.java
│       │               ├── Field.java
│       │               ├── Message.java
│       │               ├── MessageType.java
│       │               ├── MessageTypes.java
│       │               ├── ParseException.java
│       │               ├── ParseFailedException.java
│       │               ├── PartialParseException.java
│       │               ├── Protocol.java
│       │               ├── Session.java
│       │               ├── Tags.java
│       │               ├── Version.java
│       │               ├── Versions.java
│       │               └── package-info.java
│       └── test/
│           └── java/
│               └── falcon/
│                   └── fix/
│                       ├── MemoryMeterTest.java
│                       └── ProtocolTest.java
├── falcon-perf-test/
│   ├── bin/
│   │   └── falcon-perf-test
│   ├── pom.xml
│   └── src/
│       └── main/
│           └── java/
│               └── falcon/
│                   └── fix/
│                       └── perf/
│                           └── ClientPerfTest.java
└── pom.xml
Download .txt
SYMBOL INDEX (62 symbols across 16 files)

FILE: falcon-perf-test/src/main/java/falcon/fix/perf/ClientPerfTest.java
  class ClientPerfTest (line 14) | public class ClientPerfTest {
    method main (line 15) | public static void main(String[] args) throws Exception {
    method connect (line 97) | private static SocketChannel connect(String host, int port) throws Exc...
    method nanosToMicros (line 107) | private static double nanosToMicros(double nano) {

FILE: falcon/src/main/java/falcon/fix/ByteString.java
  class ByteString (line 5) | public final class ByteString {
    method of (line 11) | public static ByteString of(ByteBuffer buf, int len) {
    method ByteString (line 17) | public ByteString(byte[] data) {

FILE: falcon/src/main/java/falcon/fix/Field.java
  class Field (line 8) | public class Field {
    method Field (line 13) | public Field(int tag, Object value) {
    method tag (line 18) | public int tag() {
    method value (line 22) | public Object value() {

FILE: falcon/src/main/java/falcon/fix/Message.java
  class Message (line 12) | public class Message {
    method Message (line 25) | public Message(MessageType type, List<Field> fields) {
    method type (line 30) | public MessageType type() {
    method fields (line 34) | public List<Field> fields() {
    class Builder (line 41) | public static class Builder {
      method Builder (line 45) | public Builder(MessageType type) {
      method add (line 49) | public Builder add(Field field) {
      method build (line 54) | public Message build() {

FILE: falcon/src/main/java/falcon/fix/MessageType.java
  class MessageType (line 6) | public class MessageType {
    method MessageType (line 10) | public MessageType(String value) {
    method value (line 14) | public String value() {

FILE: falcon/src/main/java/falcon/fix/MessageTypes.java
  class MessageTypes (line 3) | public class MessageTypes {

FILE: falcon/src/main/java/falcon/fix/ParseException.java
  class ParseException (line 3) | public class ParseException extends Exception {
    method ParseException (line 4) | public ParseException() {
    method ParseException (line 7) | public ParseException(String message) {

FILE: falcon/src/main/java/falcon/fix/ParseFailedException.java
  class ParseFailedException (line 3) | public class ParseFailedException extends ParseException {
    method ParseFailedException (line 4) | public ParseFailedException(String message) {

FILE: falcon/src/main/java/falcon/fix/PartialParseException.java
  class PartialParseException (line 3) | public class PartialParseException extends ParseException {

FILE: falcon/src/main/java/falcon/fix/Protocol.java
  class Protocol (line 10) | public class Protocol {
    method format (line 25) | public static void format(ByteBuffer buf, int tag, byte[] value) {
    method formatInt (line 35) | public static void formatInt(ByteBuffer buf, int tag, int value) {
    method formatString (line 42) | public static void formatString(ByteBuffer buf, int tag, String value) {
    method formatCheckSum (line 51) | public static void formatCheckSum(ByteBuffer buf, int tag, int value) {
    method writeInt (line 64) | public static void writeInt(ByteBuffer buf, int n) {
    method match (line 85) | public static void match(ByteBuffer buf, int tag) throws ParseException {
    method matchInt (line 91) | public static int matchInt(ByteBuffer buf, int tag) throws ParseExcept...
    method parseInt (line 96) | public static int parseInt(ByteBuffer buf, byte delimiter) {
    method parseString (line 114) | public static ByteString parseString(ByteBuffer buf, byte delimiter) {
    method matchMsgType (line 127) | public static MessageType matchMsgType(ByteBuffer buf) throws ParseExc...
    method matchTag (line 151) | public static void matchTag(ByteBuffer buf, int tag) throws ParseExcep...

FILE: falcon/src/main/java/falcon/fix/Session.java
  class Session (line 14) | public class Session {
    method Session (line 28) | public Session(SocketChannel socket, Version version, String senderCom...
    method updateTime (line 35) | public void updateTime() {
    method send (line 39) | public void send(Message msg) throws Exception {
    method recv (line 78) | public Message recv() throws Exception {
    method sum (line 117) | private static int sum(ByteBuffer buf) {
    method sum (line 121) | private static int sum(ByteBuffer buf, int start, int end) {

FILE: falcon/src/main/java/falcon/fix/Tags.java
  class Tags (line 3) | public class Tags {

FILE: falcon/src/main/java/falcon/fix/Version.java
  class Version (line 13) | public class Version {
    method Version (line 17) | public Version(String value) {
    method Version (line 21) | public Version(byte[] value) {
    method value (line 25) | public byte[] value() {

FILE: falcon/src/main/java/falcon/fix/Versions.java
  class Versions (line 3) | public class Versions {

FILE: falcon/src/test/java/falcon/fix/MemoryMeterTest.java
  class MemoryMeterTest (line 11) | public class MemoryMeterTest {
    method footprint (line 15) | @Test
    method measure (line 31) | private void measure(Object obj) {

FILE: falcon/src/test/java/falcon/fix/ProtocolTest.java
  class ProtocolTest (line 8) | public class ProtocolTest {
    method writeInt (line 9) | @Test
    method writeInt (line 16) | private static String writeInt(int n) throws Exception {
    method parseInt (line 25) | @Test
    method parseInt (line 32) | private static int parseInt(String s) throws Exception {
Condensed preview — 24 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (34K chars).
[
  {
    "path": ".gitignore",
    "chars": 7,
    "preview": "target\n"
  },
  {
    "path": "LICENSE",
    "chars": 1396,
    "preview": "Copyright (C) 2013 Pekka Enberg\n\nFalcon is distributed under the 2-clause BSD license:\n\n    Redistribution and use in so"
  },
  {
    "path": "README.md",
    "chars": 3317,
    "preview": "# Falcon\n\nFalcon is a high performance, low latency FIX engine for the JVM. It provides\nan API that enables FIX connecti"
  },
  {
    "path": "falcon/pom.xml",
    "chars": 1969,
    "preview": "<?xml version=\"1.0\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-ins"
  },
  {
    "path": "falcon/src/main/java/falcon/fix/ByteString.java",
    "chars": 427,
    "preview": "package falcon.fix;\n\nimport java.nio.ByteBuffer;\n\npublic final class ByteString {\n  final byte[] data;\n\n  /**\n   * Retur"
  },
  {
    "path": "falcon/src/main/java/falcon/fix/Field.java",
    "chars": 355,
    "preview": "package falcon.fix;\n\nimport java.nio.ByteBuffer;\n\n/**\n * A field is composed of a tag and value pair.\n */\npublic class F"
  },
  {
    "path": "falcon/src/main/java/falcon/fix/Message.java",
    "chars": 1174,
    "preview": "package falcon.fix;\n\nimport static falcon.fix.Tags.*;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport jav"
  },
  {
    "path": "falcon/src/main/java/falcon/fix/MessageType.java",
    "chars": 259,
    "preview": "package falcon.fix;\n\n/**\n * A message type specifies which fields a message contains.\n */\npublic class MessageType {\n\n  "
  },
  {
    "path": "falcon/src/main/java/falcon/fix/MessageTypes.java",
    "chars": 710,
    "preview": "package falcon.fix;\n\npublic class MessageTypes {\n\n  public static final MessageType Heartbeat      = new MessageType(\"0\""
  },
  {
    "path": "falcon/src/main/java/falcon/fix/ParseException.java",
    "chars": 170,
    "preview": "package falcon.fix;\n\npublic class ParseException extends Exception {\n  public ParseException() {\n  }\n\n  public ParseExce"
  },
  {
    "path": "falcon/src/main/java/falcon/fix/ParseFailedException.java",
    "chars": 154,
    "preview": "package falcon.fix;\n\npublic class ParseFailedException extends ParseException {\n  public ParseFailedException(String mes"
  },
  {
    "path": "falcon/src/main/java/falcon/fix/PartialParseException.java",
    "chars": 83,
    "preview": "package falcon.fix;\n\npublic class PartialParseException extends ParseException {\n}\n"
  },
  {
    "path": "falcon/src/main/java/falcon/fix/Protocol.java",
    "chars": 3944,
    "preview": "package falcon.fix;\n\nimport static falcon.fix.MessageTypes.*;\n\nimport java.nio.ByteBuffer;\n\n/**\n * On-wire protocol pars"
  },
  {
    "path": "falcon/src/main/java/falcon/fix/Session.java",
    "chars": 4123,
    "preview": "package falcon.fix;\n\nimport static falcon.fix.Tags.*;\nimport java.nio.channels.*;\nimport java.text.*;\nimport java.util.*"
  },
  {
    "path": "falcon/src/main/java/falcon/fix/Tags.java",
    "chars": 503,
    "preview": "package falcon.fix;\n\npublic class Tags {\n\n  public static final int BeginString   = 8;\n  public static final int BodyLen"
  },
  {
    "path": "falcon/src/main/java/falcon/fix/Version.java",
    "chars": 764,
    "preview": "package falcon.fix;\n\n/**\n * A version specifies which base standard is followed in a session.\n *\n * Session version is s"
  },
  {
    "path": "falcon/src/main/java/falcon/fix/Versions.java",
    "chars": 447,
    "preview": "package falcon.fix;\n\npublic class Versions {\n\n  /**\n   * FIX 4.1 based sessions.\n   */\n  public static Version FIX_4_1 ="
  },
  {
    "path": "falcon/src/main/java/falcon/fix/package-info.java",
    "chars": 56,
    "preview": "/**\n * Falcon FIX core classes.\n */\npackage falcon.fix;\n"
  },
  {
    "path": "falcon/src/test/java/falcon/fix/MemoryMeterTest.java",
    "chars": 1099,
    "preview": "package falcon.fix;\n\nimport static falcon.fix.MessageTypes.*;\nimport static falcon.fix.Versions.*;\nimport static falcon."
  },
  {
    "path": "falcon/src/test/java/falcon/fix/ProtocolTest.java",
    "chars": 1048,
    "preview": "package falcon.fix;\n\nimport static org.junit.Assert.*;\nimport java.nio.charset.*;\nimport org.junit.Test;\nimport java.nio"
  },
  {
    "path": "falcon-perf-test/bin/falcon-perf-test",
    "chars": 336,
    "preview": "#!/bin/sh\n\nif [ -z \"$JAVACMD\" ] ; then\n  if [ -z \"$JAVA_HOME\" ] ; then\n    JAVACMD='java'\n  else\n    JAVACMD=\"$JAVA_HOME"
  },
  {
    "path": "falcon-perf-test/pom.xml",
    "chars": 1986,
    "preview": "<?xml version=\"1.0\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-ins"
  },
  {
    "path": "falcon-perf-test/src/main/java/falcon/fix/perf/ClientPerfTest.java",
    "chars": 3505,
    "preview": "package falcon.fix.perf;\n\nimport static java.net.StandardSocketOptions.TCP_NODELAY;\nimport static falcon.fix.MessageType"
  },
  {
    "path": "pom.xml",
    "chars": 3072,
    "preview": "<?xml version=\"1.0\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-ins"
  }
]

About this extraction

This page contains the full source code of the penberg/falcon GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 24 files (30.2 KB), approximately 8.7k tokens, and a symbol index with 62 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!