Skip to content

About

iperf3KMP is a cross-platform network performance testing app for Android, iOS, and Desktop GUI / CLI (macOS, Windows, Linux), built from a single Kotlin Multiplatform codebase with a shared Compose UI. iperf3KMP uses an embedded iPerf3 3.21

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

81 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Network Testing (iperf3) GUI and CLI

iperf3KMP is a cross-platform network performance testing app for Android, iOS, and desktop (macOS, Windows, Linux), built from a single Kotlin Multiplatform codebase with a shared Compose UI.

Highlights:

  • Real iperf3, not a simulation — runs an embedded iperf3 3.21 client in-process (JNI on Android/desktop, Kotlin/Native cinterop on iOS) against the same shared C core on every platform.
  • Genuine measurements — real TCP/UDP throughput, jitter, and loss, not canned or mocked output.
  • Built-in history — results are saved locally via Room/SQLite, with a history view and CSV export.
  • GUI and CLI — the desktop build ships both a Compose GUI and a standalone CLI tool.
  • Native installers — .dmg, .msi, .deb, and .rpm packages for each desktop OS.

iPerf3 Network Tester

Documentation: see docs/README.md for an index of the architecture, per-platform build, and research docs.

Support: report bugs and ask questions in GitHub Issues. The maintainer address inside the Linux packages is a GitHub no-reply address, so email sent there isn't delivered.

Platforms Supported

  1. Android
    • arm64 physical and simulator
    • x86_64 simulator only
  2. iOS
    • arm64 physical and simulator
    • x86_64 simulator is not supported
  3. Desktop GUI (JVM — macOS / Linux / Windows)
    • macOS – aarch64 (M series only; no x86_64)
    • Linux – x86_64
      • rpm - Fedora/RHEL
      • deb - Debian/Ubuntu
    • Linux – arm64
      • rpm - Fedora/RHEL
      • deb - Debian/Ubuntu
    • Windows
      • x86_64
      • arm64 (partially x86_64 via Prism translation)
  4. Desktop CLI (macOS / Linux / Windows)
    • Same platforms as GUI

Installation

Note

Install using a single command

Linux / macOS

curl -fsSL https://raw.githubusercontent.com/jerryabramson/iperf3-kmp/master/install.sh | bash

Windows (PowerShell)

irm https://raw.githubusercontent.com/jerryabramson/iperf3-kmp/master/install.ps1 | iex

Windows isn't distributed as a GitHub release asset — the script above just points you at the Microsoft Store listing (pending certification) or the platform build guide below.


Platform Installers

Important

Release 1.0.1: iOS and Android only

1.0.1 is out for iOS (TestFlight public beta) and Android (Google Play testing). The desktop installers further down are still 1.0.0; desktop 1.0.1 hasn't been released yet.

Platform Version How to install
iOS / iPadOS 1.0.1 Open the Apple TestFlight link on the device (installs the TestFlight app first if needed).
Android 1.0.1 1. Join the iperf3kmp-testers Google Group with the Google account your phone uses.
2. Open the Google Play test opt-in link on the phone, signed in with that account, accept, and install from Play. It can take a few minutes after joining before the link works ("item not found" until then).

Release 0.1 Installers

Installer Operating System architecture
iperf3KMP-1.0.0.dmg macOS aarch64
iperf3kmp_1.0.0_arm64.deb Debian/Ubuntu arm64
iperf3kmp-1.0.0-1.aarch64.rpm Fedora/RHEL aarch64
Windows ARM64 build guide — Store listing pending certification Windows on ARM arm64
Installer Operating System architecture
Windows x86_64 build guide — Store listing pending certification Windows x86_64
iperf3kmp_1.0.0_amd64.deb Debian/Ubuntu x86_64
iperf3kmp-1.0.0-1.x86_64.rpm Fedora/RHEL x86_64

Source Code

artifact Format
zip zipfile
tar.gz tarfile

Tip

When building from source code, there are three options to download:

  1. Clone and build to a running app on the current platform/architecture:
git clone https://github.com/jerryabramson/iperf3-kmp --recursive
cd iperf3-kmp/
  1. The full esnet/iperf source tree isn't included in this repo
  • it's a git submodule pinned to the 3.21 tag, which is required for every target:

    • Android iOS and Desktop all link against it
  • After cloning, if the third_party/iperf subdirectory is empty, run:

git submodule update --init --recursive
  1. If the source code is downloaded as a zipfile or tar.gz
cd third_party
rmdir iperf
git clone --branch 3.21 --depth 1 https://github.com/esnet/iperf.git iperf
  • Run desktop app (Linux, macOS, or Windows — on Windows use gradlew.bat, see the Windows section below)
./gradlew :desktopApp:run

Code Layout

  • /iosApp contains an iOS application.
    • Even if you’re sharing your UI with Compose Multiplatform, you need this entry point for your iOS app.
    • This is also where you should add SwiftUI code for your project.
  • /androidApp is the Android application shell.
    • MainActivity.kt is the entry point — a thin host for the shared Compose UI.
  • /desktopApp is the JVM desktop application shell (macOS / Linux / Windows).
    • main.kt is the entry point — it opens the Compose GUI by default, or dispatches to the cli package's CliRunner instead if command-line arguments are passed.
    • Desktop packaging (.dmg / .msi / .deb / .rpm) is configured in build.gradle.kts.
  • /shared is for code that will be shared across your Compose Multiplatform applications.
    • commonMain is for code that’s common for all targets.
    • Platform-specific subfolders — compiled only for the platform named in the folder:
      • androidMain — Android specific code.
      • jvmMain — Desktop (JVM) specific code.
      • iosMain — iOS specific code (Kotlin).
        • For example, if you want to use Apple’s CoreCrypto for the iOS part of your Kotlin app, this folder would be the right place for such calls.

Building and running recipes, per platform

Build using IDE

Tip

Use the run configurations provided by the run widget in your IDE's toolbar

Build from the command-line

Warning

Gradle command-line syntax and options

Android

Needs the Android SDK (sdk.dir in local.properties, or ANDROID_HOME). To build only:

./gradlew :androidApp:assembleDebug

To also boot an emulator and run the app on it, entirely from the command line.

  • To see the available AVDs:
$ANDROID_HOME/emulator/emulator -list-avds
  • swap Pixel_8 for one of your own)
$ANDROID_HOME/emulator/emulator -avd Pixel_8 &                     # boots with a visible window
$ANDROID_HOME/platform-tools/adb wait-for-device
until [ "$($ANDROID_HOME/platform-tools/adb shell getprop sys.boot_completed | tr -d '\r')" = "1" ]; do sleep 2; done
./gradlew :androidApp:installDebug                                  # builds + installs to the running emulator
$ANDROID_HOME/platform-tools/adb shell am start \
  -n com.jabramson.iperf3_network_tester_kmp/.MainActivity

iOS

  • macOS + Xcode only — build/run is managed by Xcode's own tooling, not Gradle.
  • Gradle's Kotlin Multiplatform plugin only builds the shared Kotlin framework, not the final signed .app).
  • Easiest is opening iosApp/iosApp.xcodeproj in Xcode and running from there
    • The application can also be built and launched on a Simulator entirely from the command line.
    • no Xcode UI required.
  • Simulator builds need no Apple account. To run on your own iPhone/iPad, put your Team ID and a bundle-ID prefix in a gitignored iosApp/Configuration/LocalSigning.xcconfig (copy LocalSigning.xcconfig.template) — see docs/platform-builds/ios.md.

Build from command-line on macOS

# opens the Simulator window first, so it's visible throughout
open -a Simulator

# skip if a simulator is already booted
xcrun simctl boot "iPhone 17"

# Build and install
xcodebuild -project iosApp/iosApp.xcodeproj -scheme iosApp -sdk iphonesimulator -configuration Debug \
  -derivedDataPath build/ios build
xcrun simctl install booted build/ios/Build/Products/Debug-iphonesimulator/iperf3KMP.app
xcrun simctl launch booted com.jabramson.iperf3-network-tester-kmp

Tip

simctl boot alone starts the device headlessly with no visible window — open -a Simulator first is what actually puts it on screen.


Desktop — macOS / Linux

Requires a clang on PATH in order to compile the native iperf3/printf-formatting JNI bridges at build time; see CLAUDE.md's "Native iperf3 client" section):

 # Normal build/run
 gradlew :desktopApp:run
 # hot reload during development
 gradlew :desktopApp:hotRun --auto   

Desktop — Windows

  • Windows is now supported.
    • However, it has numerous special requirements and limitations
      • Architectural Difference: Does not reuse the in-process JNI path the other desktop targets use
      • instead, a bundled, Gradle-built-from-source iperf3.exe runs as a real subprocess (ProcessBuilder).
  • Special Requirements:
    • Cygwin installed at C:\cygwin64 with the gcc-core and make packages
      • This builds the iperf3.exe executable itself (Cygwin's own gcc, not clang;
        • Cygwin's bundled clang can't build against Cygwin's own newer headers.
    • A native Windows LLVM clang (e.g. winget install LLVM.LLVM)
      • builds the JNI printf-formatting helper, same as macOS/Linux above.
        • On Windows, clang takes its C headers and libraries from Visual Studio, so also install the Visual Studio Build Tools with the "Desktop development with C++" workload (add the ARM64 build tools on a Windows-on-Arm machine).
        • Without it the build fails with 'stdio.h' file not found.
    • The WiX Toolset — required by jpackage to emit the .msi.
gradlew.bat :desktopApp:run
gradlew.bat :desktopApp:packageMsi

For the full story of why this was originally rejected and what changed. An MSI built on a Windows ARM64 machine has a native ARM64 JVM (built and installed on a Parallels VM); the x64 MSI also runs there under Prism. Only iperf3.exe is x86_64 in both (Cygwin has no ARM64 port); a native ARM64 iperf3.exe is planned but not started — see WINDOWS_ARM64_IPERF3_PLAN.md.


Desktop — command-line mode (without a GUI)

  • Pass any arguments and the desktop app runs a real iperf3 test from the terminal instead of opening the GUI — the exact same engine (real libiperf, live output parsing, stall detection), just rendered with ANSI escape codes instead of Compose widgets.

  • The packaged launcher (iperf3KMP/iperf3KMP.bat / iperf3KMP.ps1) serves both uses; with Gradle, pass args via --args:

  • Once the app is installed from a package (.deb/.rpm/.dmg/.msi):

  • finds the installed launcher at its OS-specific location and run it, so you don't need to know jpackage's per-platform install layout:

# macOS/Linux
./bin/iperf3kmp my-iperf3-server.example.com -t 10 -P 4

# Windows Powershell
.\bin\iperf3kmp.ps1 my-iperf3-server.example.com -t 10 -P 4
 
# Windows BAT
.\bin\iperf3kmp.bat my-iperf3-server.example.com -t 10 -P 4 

Example Execution

command-line execution

  • See desktopApp/.../cli/CliArgs.kt's usage() for the full flag list.
  • The progress track uses ▶/◀, which ordinary terminal fonts include. With a Nerd Font (e.g. Meslo) set IPERF3KMP_NERD_FONT=1 (export in your shell profile, or setx IPERF3KMP_NERD_FONT 1 on Windows) for the rounded Powerline caps instead.
  • ANSI output works out of the box on Windows too, and falls back to plain text (no escape codes) when TERM looks like a dumb terminal, so redirected-to-a-file and CI/log-capture output stays readable.
  • When checking how the live output actually looks (cursor positioning, in-place redraws, column alignment), test via the packaged binary (bin/iperf3kmp/iperf3KMP.exe) or the built app directly — not ./gradlew :desktopApp:run, even with --args/--console=plain:
    • Gradle wraps the forked JVM's stdout, so it isn't a real TTY from the process's own perspective.
    • Buffering, isatty() detection, and terminal-width queries can all behave differently than a genuine terminal.
    • This affects exactly what this mode requires: absolute cursor positioning and live in-place redraws.

Desktop packaging

Platform task
macOS ./gradlew :desktopApp:packageDmg
macOS — local dev build, skips notarization (see important note below) ./gradlew :desktopApp:packageDmgLocal
Debian/Ubuntu Linux x86_64 ./gradlew :desktopApp:packageDeb
Fedora/Red Hat Linux x86_64 * ./gradlew :desktopApp:packageRpm
Fedora/Red Hat aarch64 * ./gradlew :desktopApp:packageRpm
Debian/Ubuntu Linux x86_64 or aarch64 - on a non-Debian host (Fedora/RHEL, or macOS with Docker Desktop) scripts/packageDebianFromContainer.sh
Fedora/RHEL x86_64 or aarch64 - on a non-RPM host (Debian/Ubuntu, or macOS with Docker Desktop) scripts/packageRpmFromContainer.sh
Windows x86_64 gradlew.bat :desktopApp:packageMsi
Windows ARM64 (native ARM64 JVM; bundled iperf3.exe is x86_64 under Prism emulation — see WINDOWS_ARM64_IPERF3_PLAN.md) gradlew.bat :desktopApp:packageMsi

Important

packageDmg always runs a real notarytool submit --wait round trip to Apple's notarization service afterward (when desktopApp.macNotarizationProfile is configured) — this can take a while, and Apple's notary service enforces its own rate limits, so running packageDmg repeatedly in quick succession during local iteration risks hitting them. Use ./gradlew :desktopApp:packageDmgLocal instead for local testing: same signed .dmg, but it skips notarization/stapling entirely. Only use plain packageDmg when you actually intend to distribute the result — a packageDmgLocal build isn't notarized, so Gatekeeper will flag it for anyone it's downloaded to.

Tip

Both container-based scripts auto-detect Podman or Docker (whichever is on PATH) and build a native, non-emulated Linux container matching the host's CPU - including on Apple Silicon or Intel Macs via Docker Desktop, since it runs a real Linux VM matching the host architecture. Verified via Podman on Fedora x86_64 and Fedora aarch64, and via Docker Desktop on macOS (Apple Silicon) producing both iperf3kmp_1.0.0_arm64.deb and iperf3kmp-1.0.0-1.aarch64.rpm.

Caution

See Gotcha's in CLAUDE.md

Tip

  • Note: the third_party/iperf submodule points at the public esnet/iperf project
  • Therefore, no authentication is required after cloning:
    • Run git submodule update --init --recursive

About

iperf3KMP is a cross-platform network performance testing app for Android, iOS, and Desktop GUI / CLI (macOS, Windows, Linux), built from a single Kotlin Multiplatform codebase with a shared Compose UI. iperf3KMP uses an embedded iPerf3 3.21

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages