-
Notifications
You must be signed in to change notification settings - Fork 24
Sderosa/data tracks throughput #111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
stephen-derosa
wants to merge
1
commit into
livekit:main
Choose a base branch
from
stephen-derosa:sderosa/data_tracks_throughput
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| *env*/ | ||
| */__pycache__/ | ||
| *throughput_results/* |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| # Copyright 2026 LiveKit, Inc. | ||
| # | ||
| # Standalone CMake build for the data-track throughput experiment. | ||
| # All paths are relative to CMAKE_CURRENT_SOURCE_DIR so this directory | ||
| # can be moved or renamed freely. | ||
|
|
||
| cmake_minimum_required(VERSION 3.20) | ||
| project(DataTrackThroughput LANGUAGES CXX) | ||
|
|
||
| set(CMAKE_CXX_STANDARD 17) | ||
| set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||
|
|
||
| # ---- Dependencies -------------------------------------------------------- | ||
|
|
||
| find_package(LiveKit CONFIG REQUIRED) | ||
|
|
||
| find_package(nlohmann_json 3.11 QUIET) | ||
| if(NOT nlohmann_json_FOUND) | ||
| include(FetchContent) | ||
| FetchContent_Declare( | ||
| nlohmann_json | ||
| GIT_REPOSITORY https://github.com/nlohmann/json.git | ||
| GIT_TAG v3.11.3 | ||
| GIT_SHALLOW TRUE | ||
| ) | ||
| FetchContent_MakeAvailable(nlohmann_json) | ||
| endif() | ||
|
|
||
| # ---- Targets ------------------------------------------------------------- | ||
|
|
||
| set(_targets DataTrackThroughputProducer DataTrackThroughputConsumer) | ||
|
|
||
| add_executable(DataTrackThroughputProducer producer.cpp) | ||
| add_executable(DataTrackThroughputConsumer consumer.cpp) | ||
|
|
||
| foreach(_target ${_targets}) | ||
| target_include_directories(${_target} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}") | ||
| target_link_libraries(${_target} PRIVATE LiveKit::livekit nlohmann_json::nlohmann_json) | ||
| endforeach() | ||
|
|
||
| # ---- RPATH --------------------------------------------------------------- | ||
|
|
||
| if(UNIX) | ||
| if(APPLE) | ||
| set_target_properties(${_targets} PROPERTIES | ||
| BUILD_RPATH "@loader_path" | ||
| INSTALL_RPATH "@loader_path" | ||
| ) | ||
| else() | ||
| set_target_properties(${_targets} PROPERTIES | ||
| BUILD_RPATH "$ORIGIN" | ||
| INSTALL_RPATH "$ORIGIN" | ||
| BUILD_RPATH_USE_ORIGIN TRUE | ||
| ) | ||
| endif() | ||
| endif() | ||
|
|
||
| # ---- Copy SDK shared libraries next to executables ----------------------- | ||
|
|
||
| get_target_property(_lk_location LiveKit::livekit LOCATION) | ||
| if(_lk_location) | ||
| get_filename_component(_lk_lib_dir "${_lk_location}" DIRECTORY) | ||
| else() | ||
| get_target_property(_lk_location LiveKit::livekit IMPORTED_LOCATION) | ||
| if(NOT _lk_location) | ||
| get_target_property(_lk_location LiveKit::livekit IMPORTED_LOCATION_RELEASE) | ||
| endif() | ||
| if(NOT _lk_location) | ||
| get_target_property(_lk_location LiveKit::livekit IMPORTED_LOCATION_DEBUG) | ||
| endif() | ||
| if(_lk_location) | ||
| get_filename_component(_lk_lib_dir "${_lk_location}" DIRECTORY) | ||
| endif() | ||
| endif() | ||
|
|
||
| if(_lk_lib_dir) | ||
| if(WIN32) | ||
| file(GLOB _sdk_shared_libs "${_lk_lib_dir}/../bin/*.dll" "${_lk_lib_dir}/*.dll") | ||
| elseif(APPLE) | ||
| file(GLOB _sdk_shared_libs "${_lk_lib_dir}/*.dylib") | ||
| else() | ||
| file(GLOB _sdk_shared_libs "${_lk_lib_dir}/*.so" "${_lk_lib_dir}/*.so.*") | ||
| endif() | ||
|
|
||
| foreach(_target ${_targets}) | ||
| foreach(_lib ${_sdk_shared_libs}) | ||
| get_filename_component(_lib_name "${_lib}" NAME) | ||
| add_custom_command(TARGET ${_target} POST_BUILD | ||
| COMMAND ${CMAKE_COMMAND} -E copy_if_different | ||
| "${_lib}" "$<TARGET_FILE_DIR:${_target}>/${_lib_name}" | ||
| COMMENT "Copying ${_lib_name} next to ${_target}" | ||
| ) | ||
| endforeach() | ||
| endforeach() | ||
| endif() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,273 @@ | ||||||||||||||||||||||||||
| # Data Track Throughput Experiment | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Coordinated producer and consumer for benchmarking `LocalDataTrack` / | ||||||||||||||||||||||||||
| `RemoteDataTrack` throughput across a sweep of payload sizes and publish rates. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## What It Does | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - `producer.cpp` | ||||||||||||||||||||||||||
| - Publishes a data track named `data-track-throughput` | ||||||||||||||||||||||||||
| - Runs a default sweep of payload sizes and publish rates (see | ||||||||||||||||||||||||||
| **Test Bounds** below) | ||||||||||||||||||||||||||
| - Calls the consumer over RPC before and after each scenario | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - `consumer.cpp` | ||||||||||||||||||||||||||
| - Registers a room data-frame callback for the producer's data track | ||||||||||||||||||||||||||
| - Receives every frame and records arrival timestamps | ||||||||||||||||||||||||||
| - Logs validation warnings (size mismatches, header mismatches, etc.) to stderr | ||||||||||||||||||||||||||
| - Tracks duplicates and missing messages | ||||||||||||||||||||||||||
| - Appends raw data to scenario-level and per-message CSV files | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Design Principles | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| - **Raw data only in CSV.** The consumer writes only directly measured values | ||||||||||||||||||||||||||
| (counts, byte totals, microsecond timestamps). All derived metrics (throughput, | ||||||||||||||||||||||||||
| latency percentiles, delivery ratio, etc.) are computed at analysis time by | ||||||||||||||||||||||||||
| `scripts/plot_throughput.py`. | ||||||||||||||||||||||||||
| - **Fixed packet size per scenario.** Each scenario uses a single | ||||||||||||||||||||||||||
| `packet_size_bytes`. This ensures every message in a run is the same size, | ||||||||||||||||||||||||||
| making aggregate measurements unambiguous. | ||||||||||||||||||||||||||
| - **Minimal measurement overhead.** The hot `onDataFrame` callback captures the | ||||||||||||||||||||||||||
| arrival timestamp first, then appends to an in-memory vector under a brief | ||||||||||||||||||||||||||
| mutex. File I/O happens only at finalization after all data is collected. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ## Test Bounds | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| All bounds are defined in `common.h`. A scenario is any combination of | ||||||||||||||||||||||||||
| (payload size, publish rate) that passes all three constraints below. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### Hard Limits | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| | Parameter | Min | Max | | ||||||||||||||||||||||||||
| |-----------|-----|-----| | ||||||||||||||||||||||||||
| | Packet size | 1 KiB | 256 MiB | | ||||||||||||||||||||||||||
| | Publish rate | 1 Hz | 50k Hz | | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### Data-Rate Budget | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Every scenario must satisfy: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||
| packet_size_bytes * desired_rate_hz <= 10 Gbps (1.25 GB/s) | ||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| This naturally allows small messages at very high rates and large messages at | ||||||||||||||||||||||||||
| low rates while preventing any single scenario from attempting an unreasonable | ||||||||||||||||||||||||||
| throughput that would destabilize the connection. | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ### Default Sweep Grid | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| The default sweep iterates over 13 payload sizes and 13 publish rates, skipping | ||||||||||||||||||||||||||
| any combination that exceeds the data-rate budget: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| **Payload sizes:** 1 KiB, 4 KiB, 16 KiB, 64 KiB, 128 KiB, 256 KiB, 512 KiB, | ||||||||||||||||||||||||||
| 1 MiB, 2 MiB, 4 MiB, 16 MiB, 64 MiB, 256 MiB | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| **Publish rates:** 1, 5, 10, 25, 50, 100, 200, 500, 1k, 5k, 10k, 20k, 50k Hz | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| The budget clips larger payloads to lower rates. For example: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| | Payload | Max rate allowed | | ||||||||||||||||||||||||||
| |---------|-----------------| | ||||||||||||||||||||||||||
| | 1 KiB | 50k Hz (all rates) | | ||||||||||||||||||||||||||
| | 16 KiB | 50k Hz (all rates) | | ||||||||||||||||||||||||||
| | 64 KiB | 10k Hz | | ||||||||||||||||||||||||||
| | 256 KiB | 1k Hz | | ||||||||||||||||||||||||||
| | 1 MiB | 1k Hz | | ||||||||||||||||||||||||||
| | 4 MiB | 200 Hz | | ||||||||||||||||||||||||||
| | 64 MiB | 10 Hz | | ||||||||||||||||||||||||||
| | 256 MiB | 1 Hz | | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| The budget clips larger payloads to lower rates. For example: | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| | Payload | Max rate allowed | | ||||||||||||||||||||||||||
| |---------|-----------------| | ||||||||||||||||||||||||||
| | 1 KiB | 50k Hz (all rates) | | ||||||||||||||||||||||||||
| | 16 KiB | 50k Hz (all rates) | | ||||||||||||||||||||||||||
| | 64 KiB | 10k Hz | | ||||||||||||||||||||||||||
| | 256 KiB | 1k Hz | | ||||||||||||||||||||||||||
| | 1 MiB | 1k Hz | | ||||||||||||||||||||||||||
| | 4 MiB | 200 Hz | | ||||||||||||||||||||||||||
| | 64 MiB | 10 Hz | | ||||||||||||||||||||||||||
| | 256 MiB | 1 Hz | | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
Comment on lines
+81
to
+93
|
||||||||||||||||||||||||||
| The budget clips larger payloads to lower rates. For example: | |
| | Payload | Max rate allowed | | |
| |---------|-----------------| | |
| | 1 KiB | 50k Hz (all rates) | | |
| | 16 KiB | 50k Hz (all rates) | | |
| | 64 KiB | 10k Hz | | |
| | 256 KiB | 1k Hz | | |
| | 1 MiB | 1k Hz | | |
| | 4 MiB | 200 Hz | | |
| | 64 MiB | 10 Hz | | |
| | 256 MiB | 1 Hz | |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using
get_target_property(... LOCATION)is deprecated/disallowed under newer CMake policies (and can produce warnings/errors for imported targets). Since you already fall back toIMPORTED_LOCATION*, consider dropping theLOCATIONlookup entirely and/or using the imported location properties consistently to avoid policy/CMake-version sensitivity.