better statistics
Some checks failed
continuous-integration/drone/tag Build is failing

This commit is contained in:
Mark Nellemann 2023-06-23 19:53:52 +02:00
parent 5b5cf3f372
commit 2496338b92
7 changed files with 185 additions and 145 deletions

23
.drone.yml Normal file
View file

@ -0,0 +1,23 @@
---
kind: pipeline
name: default
type: docker
steps:
- name: test
image: eclipse-temurin:8-jdk
commands:
- ./gradlew test
- name: build
image: eclipse-temurin:8-jdk
environment:
AUTH_TOKEN: # Gitea access token ENV variable
from_secret: auth # Name of DroneCI secret exposed above
commands:
- ./gradlew build packages
- for file in build/libs/*-all.jar ; do curl --user "${DRONE_REPO_OWNER}:$${AUTH_TOKEN}" --upload-file "$${file}" "https://git.data.coop/api/packages/${DRONE_REPO_OWNER}/generic/${DRONE_REPO_NAME}/${DRONE_TAG}/$(basename $file)" ; done
- for file in build/distributions/*.deb ; do curl --user "${DRONE_REPO_OWNER}:$${AUTH_TOKEN}" --upload-file "$${file}" "https://git.data.coop/api/packages/${DRONE_REPO_OWNER}/generic/${DRONE_REPO_NAME}/${DRONE_TAG}/$(basename $file)" ; done
- for file in build/distributions/*.rpm ; do curl --user "${DRONE_REPO_OWNER}:$${AUTH_TOKEN}" --upload-file "$${file}" "https://git.data.coop/api/packages/${DRONE_REPO_OWNER}/generic/${DRONE_REPO_NAME}/${DRONE_TAG}/$(basename $file)" ; done
when:
event:
- tag

View file

@ -1,18 +1,10 @@
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java application project to get you started.
* For more details take a look at the 'Building Java & JVM projects' chapter in the Gradle
* User Manual available at https://docs.gradle.org/8.1.1/userguide/building_java_projects.html
*/
plugins {
id 'java'
id 'groovy'
id 'application'
id "com.github.johnrengelman.shadow" version "7.1.2"
id "net.nemerosa.versioning" version "2.15.1"
id "net.nemerosa.versioning" version "3.0.0"
id "com.netflix.nebula.ospackage" version "11.2.0"
id "com.github.johnrengelman.shadow" version "7.1.2"
}
repositories {
@ -24,19 +16,22 @@ dependencies {
testImplementation 'org.spockframework:spock-core:2.2-groovy-3.0'
testImplementation 'junit:junit:4.13.2'
annotationProcessor 'info.picocli:picocli-codegen:4.7.4'
implementation 'info.picocli:picocli:4.7.4'
implementation 'org.slf4j:slf4j-api:2.0.7'
implementation 'ch.qos.logback:logback-classic:1.3.8'
implementation 'info.picocli:picocli:4.7.4'
annotationProcessor 'info.picocli:picocli-codegen:4.7.4'
}
// Apply a specific Java toolchain to ease working on different environments.
java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
languageVersion = JavaLanguageVersion.of(8)
}
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
application {
// Define the main class for the application.
mainClass = 'biz.nellemann.jperf.App'
@ -47,6 +42,9 @@ tasks.named('test') {
useJUnitPlatform()
}
group = projectGroup
version = projectVersion
jar {
manifest {

3
gradle.properties Normal file
View file

@ -0,0 +1,3 @@
projectId = jperf
projectGroup = biz.nellemann.jperf
projectVersion = 0.0.1

View file

@ -26,19 +26,16 @@ public class App implements Callable<Integer> {
@CommandLine.Option(names = { "-s", "--server" }, description = "run server and wait for client")
boolean runServer = false;
@CommandLine.Option(names = { "-l", "--pkt-size" }, paramLabel = "SIZE", description = "datagram size in bytes, max 65507")
@CommandLine.Option(names = { "-l", "--pkt-size" }, paramLabel = "SIZE", description = "datagram size in bytes, max 65507 [default: ${DEFAULT-VALUE}]")
//int packetSize = 16384; // Min: 256 Max: 65507
int packetSize = 65507; // Min: 256 Max: 65507
@CommandLine.Option(names = { "-n", "--pkt-num" }, paramLabel = "NUM", description = "number of packets to send")
@CommandLine.Option(names = { "-n", "--pkt-num" }, paramLabel = "NUM", description = "number of packets to send [default: ${DEFAULT-VALUE}]")
int packetCount = 5000;
@CommandLine.Option(names = { "-p", "--port" }, paramLabel = "PORT", description = "network port")
@CommandLine.Option(names = { "-p", "--port" }, paramLabel = "PORT", description = "network port [default: ${DEFAULT-VALUE}]")
int port = 4445;
@CommandLine.Option(names = { "-w", "--send-wait" }, paramLabel = "MILLISEC", description = "delay in millis between sending packets")
long sendWait = 3;
@Override
@ -52,14 +49,10 @@ public class App implements Callable<Integer> {
runClient(remoteServer);
}
//udpServer.printSummary();
return 0;
}
// this example implements Callable, so parsing, error handling and handling user
// requests for usage help or version help can be done with one line of code.
public static void main(String... args) {
int exitCode = new CommandLine(new App()).execute(args);
System.exit(exitCode);
@ -68,51 +61,12 @@ public class App implements Callable<Integer> {
private void runClient(String remoteHost) throws InterruptedException, IOException {
long sequence = 0;
// Start client and send some messages
UdpClient udpClient = new UdpClient(remoteHost, port);
// Start datagram
Datagram datagram = new Datagram(DataType.HANDSHAKE.getValue(), packetSize, sequence++, packetCount);
udpClient.send(datagram);
Thread.sleep(100);
// TODO: Wait for ACK
datagram = udpClient.receive();
if(datagram.getType() != DataType.ACK.getValue()) {
log.warn("No ACK!");
return;
UdpClient udpClient = new UdpClient(remoteHost, port, packetCount, packetSize);
udpClient.start();
}
// Data datagrams ...
for(int i = 0; i < packetCount; i++) {
datagram = new Datagram(DataType.DATA.getValue(), packetSize, sequence++, packetCount);
udpClient.send(datagram);
Thread.sleep(sendWait);
}
// End datagram
Thread.sleep(100);
datagram = new Datagram(DataType.END.getValue(), packetSize, sequence++, packetCount);
udpClient.send(datagram);
// TODO: Wait for ACK
datagram = udpClient.receive();
if(datagram.getType() != DataType.ACK.getValue()) {
log.warn("No ACK!");
return;
}
udpClient.close();
Thread.sleep(1000);
udpClient.printStatistics();
}
private void runServer() throws SocketException, InterruptedException {
// Start server
UdpServer udpServer = new UdpServer(port);
udpServer.start();
udpServer.join();

View file

@ -0,0 +1,68 @@
package biz.nellemann.jperf;
import java.time.Duration;
import java.time.Instant;
public class Statistics {
private long packetsTransferred, packetsTransferredTotal = 0;
private long bytesTransferred, bytesTransferredTotal = 0;
private long bytesPerSec, packesPerSec = 0;
private long packetsUnacked = 0;
private Instant timestamp1 = Instant.now();
private Instant timestamp2 = Instant.now();
public void reset() {
timestamp1 = Instant.now();
}
public void tick() {
timestamp2 = Instant.now();
if(Duration.between(timestamp1, timestamp2).toMillis() >= 1000) {
// Because we do this every second ...
bytesPerSec = bytesTransferred;
packesPerSec = packetsTransferred;
timestamp1 = timestamp2;
print();
}
}
public void print() {
System.out.printf("%-30s Status: %8d pkt/s %12d B/s %10d KB/s %8d MB/s\n", Instant.now().toString(), packesPerSec, bytesPerSec, bytesPerSec/1_000, bytesPerSec/1_000_000);
}
public void summary() {
System.out.printf("%-29s Summary: %8d pkts %13d B %12d KB %10d MB %6d GB\n", Instant.now().toString(), packetsTransferredTotal, bytesTransferredTotal, bytesTransferredTotal /1_000, bytesTransferredTotal /1_000_000, bytesTransferredTotal/1_000_000_000);
}
public void ack() {
packetsUnacked--;
}
public void transferPacket() {
packetsUnacked++;
packetsTransferred++;
packetsTransferredTotal++;
}
public void transferBytes(long bytes) {
bytesTransferred += bytes;
bytesTransferredTotal += bytes;
}
public long getPacketsUnacked() {
return packetsUnacked;
}
public long getPacketsTransferredTotal() {
return packetsTransferredTotal;
}
}

View file

@ -15,6 +15,8 @@ public class UdpClient {
final Logger log = LoggerFactory.getLogger(UdpClient.class);
private Statistics statistics;
private final int port;
private final InetAddress address;
private final DatagramSocket socket;
@ -23,43 +25,81 @@ public class UdpClient {
private long packetsSent = 0;
private long bytesSent = 0;
private int packetCount;
private int packetSize;
public UdpClient(String hostname, int port) throws UnknownHostException, SocketException {
public UdpClient(String hostname, int port, int packets, int size) throws UnknownHostException, SocketException {
log.info("UdpClient() - target: {}, port: {}", hostname, port);
this.port = port;
socket = new DatagramSocket();
address = InetAddress.getByName(hostname);
this.packetCount = packets;
this.packetSize = size;
statistics = new Statistics();
}
public void send(Datagram datagram) throws IOException {
private void send(Datagram datagram) throws IOException {
DatagramPacket packet = new DatagramPacket(datagram.getPayload(), datagram.getRealLength(), address, port);
socket.send(packet);
packetsSent++;
bytesSent += datagram.getRealLength();
statistics.transferPacket();
statistics.transferBytes(datagram.getRealLength());
}
public Datagram receive() throws IOException {
private Datagram receive() throws IOException {
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
return new Datagram(buf);
}
public String sendEcho(String msg) throws IOException {
log.info("send() - msg: {}", msg);
buf = msg.getBytes();
DatagramPacket packet = new DatagramPacket(buf, buf.length, address, port);
socket.send(packet);
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
return new String( packet.getData(), 0, packet.getLength() );
}
public void close() {
private void close() {
socket.close();
}
public void printStatistics() {
System.out.printf("%s sent: %d pkts\t %d B\t %d KB\t %d MB\n", Instant.now().toString(), packetsSent, bytesSent, bytesSent/1000, bytesSent/1_000_000);
public void start() throws IOException, InterruptedException {
long sequence = 0;
// Start datagram
Datagram datagram = new Datagram(DataType.HANDSHAKE.getValue(), packetSize, sequence++, packetCount);
send(datagram);
// TODO: Wait for ACK
datagram = receive();
if(datagram.getType() != DataType.ACK.getValue()) {
log.warn("No ACK!");
return;
}
// Data datagrams ...
for(int i = 0; i < packetCount; i++) {
datagram = new Datagram(DataType.DATA.getValue(), packetSize, sequence++, packetCount);
send(datagram);
datagram = receive();
if(datagram.getType() != DataType.ACK.getValue()) {
log.warn("No ACK!");
}
statistics.tick();
}
// End datagram
//Thread.sleep(100);
datagram = new Datagram(DataType.END.getValue(), packetSize, sequence++, packetCount);
send(datagram);
// TODO: Wait for ACK
datagram = receive();
statistics.ack();
if(datagram.getType() != DataType.ACK.getValue()) {
log.warn("No ACK!");
return;
}
Thread.sleep(100);
close();
statistics.summary();
}
}

View file

@ -5,8 +5,6 @@ import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.time.Duration;
import java.time.Instant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -15,13 +13,9 @@ public class UdpServer extends Thread {
final Logger log = LoggerFactory.getLogger(UdpServer.class);
private final DatagramSocket socket;
private byte[] buf = new byte[256];
long pktsReceived, pktsReceivedTotal = 0;
long bytesReceived, bytesReceivedTotal = 0;
long bytesPerSec, pktsPerSec = 0;
public UdpServer(int port) throws SocketException {
log.info("UdpServer()");
@ -46,29 +40,11 @@ public class UdpServer extends Thread {
}
public void printStatistics() {
// Because we do this every second ...
bytesPerSec = bytesReceived;
pktsPerSec = pktsReceived;
System.out.printf("%s recv: %d pkt/s\t %d B/s\t %d KB/s\t %d MB/s\n", Instant.now().toString(), pktsPerSec, bytesPerSec, bytesPerSec/1_000, bytesPerSec/1_000_000);
pktsReceived = 0;
bytesReceived = 0;
}
public void printSummary() {
System.out.printf("%s recv: %d pkts\t %d B\t %d KB\t %d MB\n", Instant.now().toString(), pktsReceivedTotal, bytesReceivedTotal, bytesReceivedTotal/1_000, bytesReceivedTotal/1_000_000);
}
public void session() throws IOException {
Statistics statistics = new Statistics();
boolean running = true;
boolean ackEnd = false;
long thisSequence, lastSequence = 0;
Instant startInstant = Instant.now();
Instant checkInstant;
while (running) {
@ -79,61 +55,39 @@ public class UdpServer extends Thread {
int port = packet.getPort();
Datagram datagram = new Datagram(buf);
thisSequence = datagram.getCurPkt();
statistics.transferPacket();
statistics.transferBytes(datagram.getRealLength());
if(datagram.getType() == DataType.HANDSHAKE.getValue()) {
log.info("Handshake from ... {}, length: {}", address, datagram.getLength());
// Setup to receive larger datagrams
buf = new byte[datagram.getLength()];
// Send ACK
Datagram responseDatagram = new Datagram(DataType.ACK.getValue(), 32, datagram.getCurPkt(), 1);
packet = new DatagramPacket(responseDatagram.getPayload(), responseDatagram.getLength(), address, port);
socket.send(packet);
statistics.reset();
}
/*
if(datagram.getType() == DataType.DATA.getValue()) {
bytesReceived += datagram.getLength();
bytesReceivedTotal += datagram.getLength();
if(thisSequence == lastSequence + 1) {
//log.info("Data .... size: {}, sequence: {}", datagram.getLength(), thisSequence);
} else {
//log.warn("Data .... out of sequence: {} vs {}", thisSequence, lastSequence);
}
}
bytesReceived += datagram.getRealLength();
bytesReceivedTotal += datagram.getRealLength();
}*/
if(datagram.getType() == DataType.END.getValue()) {
ackEnd = true;
}
// Every second
checkInstant = Instant.now();
if(Duration.between(startInstant, checkInstant).toSeconds() >= 1) {
printStatistics();
startInstant = checkInstant;
}
if(ackEnd && pktsReceivedTotal > datagram.getMaxPkt()) {
// Send ACK
Datagram responseDatagram = new Datagram(DataType.ACK.getValue(), 32, datagram.getCurPkt(), 1);
packet = new DatagramPacket(responseDatagram.getPayload(), responseDatagram.getLength(), address, port);
socket.send(packet);
statistics.ack();
printSummary();
statistics.tick();
if(ackEnd && statistics.getPacketsTransferredTotal() > datagram.getMaxPkt()) {
running = false;
statistics.summary();
}
lastSequence = thisSequence;
pktsReceived++;
pktsReceivedTotal++;
}