SenseGlove FakeShm Module Tuning
Starting with SenseGlove Libraries v2.400.0-023e6b23c, which is at the heart of SenseCom v1.10.x and the SenseGlove Unreal Engine Plugin v2.9.x, SenseGlove has introduced a completely new communication backend called SGFakeShm.
Despite its name, SGFakeShm is not another shared memory implementation. Instead, it is a modern communication layer that supports multiple transports to imitate the legacy SharedMem behavior using alternative transports and mechanisms on both Microsoft Windows and GNU/Linux, while retaining full compatibility with the existing Shared Memory implementation.
The new module was designed to significantly improve latency, throughput, and frame rate stability while maintaining backward and forward compatibility with previous or future releases of SenseCom or the UE plugin.
Overview
Prior to this release, communication between SenseCom and applications such as Unreal Engine or Unity relied exclusively on Boost Shared Memory.
While the legacy Shared Memory provides good performance, it has several drawbacks:
- Communication is fundamentally blocking.
- Enterprise security software frequently interferes with Shared Memory.
- Multiple applications competing for Shared Memory can negatively impact performance.
- Due to its blocking/synchronous nature of the legacy
SharedMemimplementation, rendering and communication become more tightly coupled, potentially reducing frame rate where BoostSharedMembecomes the bottleneck.
The new SGFakeShm backend addresses these limitations by introducing two additional communication mechanisms/transports:
-
IPC
- Named Pipes on Microsoft Windows.
- Unix Domain Sockets on GNU/Linux.
-
TCP over loopback (localhost)
Unlike the legacy Shared Memory implementation, both IPC and TCP transports support a fully asynchronous, non-blocking architecture, unless explicitly forced to fall back to synchronous/blocking mode via the user-exposed configuration.
This allows communication to happen independently from rendering, reducing stalls and improving frame time consistency.
Backward and Forward Compatibility
One of the design goals of SGFakeShm was complete backward and forward compatibility.
Even if your application is still using an older Unreal Engine plugin, simply upgrading SenseCom allows you to benefit from the improvements made to the Shared Memory transport. The opposite is also correct, you can pair old SenseCom with newer UE plugin that relies on SGFakeShm and both still should function as expected.
Note
If a new version of SenseCom or the UE plugin paired with a version that lacks support for
SGFakeShm, using the default settings, it will always automatically fall back to the legacySharedMem. Thus, we recommend using the recent versions of both SenseCom and the UE plugin with support forSGFakeShmto be able to fully utilize the new capabilities and improvements including the new IPC and TCP transports. Otherwise, due to lack of support from one party in such setups where one side lacksSGFakeShmsupport,IPCorTCPwon't function as expected.
Since the preferred transport is only chosen and configured centrally via SenseCom and also the exchanged configurations are versioned, Unreal and Unity plugins automatically detect and follow the selected transport and their enforced settings; as a result the setting only needs to be changed in one place and no configuration from the plugin side is required at all.
This ability allows the plugins or applications to remain forward compatible with SenseCom when future versions are released, thus enables SenseCom to deliver further tweaking and performance improvements in the future.
Shared Memory Improvements
Although Shared Memory remains a blocking transport by design, it has received numerous internal optimizations. The new implementation provides:
- Reduced latency.
- Higher throughput.
- Various bug fixes.
In our benchmarking, we observed that the legacy SharedMem overhaul has dramatically improved its performance and stability, boosting throughput from only a few KB/s to roughly 7.5 GB/s in certain configurations, compared to the previous implementation.
Applications that still prefer to use SharedMem over IPC (Named Pipes on Microsoft Windows and Unix Domain Sockets on GNU/Linux), will therefore still benefit from upgrading SenseCom and the UE plugin, even without adopting the newer IPC or TCP transports.
These improvements are specifically designed to eliminate bottlenecks and improve reliability in demanding enterprise environments where shared memory can be impacted by security software.
Transport Configuration
Transport configuration is done in two parts:
- Choosing an IPC mechanism via SenseCom settings.
- Optionally, tweaking and tuning the desired transport for your hardware, operating system, and use case via
sgfakeshm-params.yml.
Choosing a Transport via SenseCom Settings
In order to choose an IPC transport/mechanism:
- Open the click on the hamburger button inside the main SenseCom user interface.
- From the open menu, choose
Settings. - Navigate to the end of the settings section.
- Click on the
IPC Methodcombo box. - Choose your desired IPC method.
Tip
You do not have to close or restart SenseCom, Unreal Editor, or your simulation to choose or change an an IPC method and its settings.
Once a new IPC method is selected, both SenseCom and your simulation should be able to pick it up almost instantaneously.
Parameter Tuning
Every SGFakeShm supported transport, IPC, TCP, and SharedMem exposes certain configurations and parameters that can further be tweaked to acheive optimal performance. While we provide sane defaults that should work well for most people out of the box, there is no single configuration that is optimal for every system, hardware, or use case. Every operating system schedules threads differently. Likewise, different communication mechanisms have different performance characteristics. For example:
- Microsoft Windows generally benefits from slightly larger timeout values.
- GNU/Linux often performs best with much lower timeout values.
IPCandTCPtransports behave differently under high load. For example, while both work best when theSocketReceiveNonBlockingparameter set totrue, their behavior differ from each other depending on the value set forSocketSendNonBlocking. Our benchmarking with a10Kpayload size reveals, on our test hardware, IPC performs better when the value for this parameter is set tofalse, while TCP performs better when it's been set totrue.- Desktop applications and VR applications often have different latency requirements.
- Low-power embedded devices may prefer lower CPU usage over absolute minimum latency.
As a result, the default configuration shipped with SenseCom has been carefully selected to provide excellent performance for the vast majority of users. So, most users do not really need to modify these values.
However, advanced users who wish to squeeze every last bit of performance out of their particular hardware can optionally do so.
Some Notes Regarding Latency and Throughput
In our benchmarks and on our test hardware, using the payload size of 1 MB, SharedMem consistently acheived the follwoing stats:
- Read Throughput: roughly
7.5 GB/s. - Write Throughput: roughly
4.0 GB/s. - Smoothed Latency on Microsoft Windows: roughly
15 ms. - Smoothed Latency on GNU/Linux: roughly
5 ms.
The same benchmark via the TCP transport and using fine-tuned settings consistently yielded:
- Read Throughput: roughly
2.1 GB/s. - Write Throughput: roughly
2.1 GB/s. - Smoothed Latency on Microsoft Windows: roughly
70 μs. - Smoothed Latency on GNU/Linux: roughly
40 μs.
The same benchmark via the IPC transport and using fine-tuned settings consistently yielded:
- Read Throughput: roughly
2.2 GB/s. - Write Throughput: roughly
2.2 GB/s. - Smoothed Latency on Microsoft Windows: roughly
100 μs. - Smoothed Latency on GNU/Linux: roughly
50 μs.
Important
While various payload sizes are supported, e.g.,
1 KB,10 KB,100 KB,1 MB, and10 MB, we recommend tuning your SenseCom installation by choosing the10 KBpayload size.The reason for this recommendation is, typically the SenseCom payload size falls somewhere in between
1 KBto10 KB. Thus, tuning using10 KBpayload size will be as close as possible to real-world SenseCom usage in production.
Note
Regardless of the payload size on Microsoft Windows, in our tests, Boost
SharedMemlatency mostly stayed above15 ms. Due to its blocking nature, this makes it less suitable for simulations that need to exceed60 FPS, especially whenSharedMemis restricted or throttled by security software. Since the rendering thread will be blocked while waiting onSharedMem, if the latency rises above1000 / 60 = 16.6666666667 ms, the framerate will suffer and you may experience jitter or lag, regardless of how powerful your hardware is.Also, there have been some reports that when
SharedMemis throttled, even if your simulation is not running, this could still cause jitter inside the Unreal Editor itself.In this case, we recommend switching to
IPCorTCPdue to their low latency. Despite their lower throughput compared to BoostSharedMem, the latency of these alternative transports is in the realm of microseconds, making them significantly faster than BoostSharedMem, whose latency is measured in milliseconds.
Benchmarking and Tuning Utilities
To assist advanced users, SenseGlove provides two simple yet powerful benchmarking applications with versatile benchmarking capabilities:
- sgfakeshm-connect-client
- sgfakeshm-core-client
These utilities are distributed through the SenseGlove Unreal Engine Plugin Azure DevOps repository and are not included in the official Fab Store release.
The utilities allow developers to:
- Benchmark latency.
- Benchmark throughput.
- Compare IPC, TCP and Shared Memory performance side by side.
- Experiment with different parameter values
- Optimize configurations for a specific operating system or hardware.
- Tune parameters for particular workloads.
Because communication performance depends on the operating system, CPU scheduler, hardware and transport type, these tools provide the easiest way to determine the optimal settings for your own environment.
sgfakeshm-connect-client
sgfakeshm-connect-client is the main benchmarking application, which acts like SenseCom. Between the two applications, the transport configuration happens on this app.
sgfakeshm-connect-client supports the following keyboard shortcuts:
ESC,Q, orCtrl+Cto exit the application.1to toggle and enable or disable theTCPtransport.2to toggle and enable or disable theIPCtransport.3to toggle and enable or disable theSharedMemtransport.Sto switch between various predefined payload sizes, e.g.,1 KB,10 KB,100 KB,1 MB, and10 MB.
It also supports the following command-line parameters in order to change the tuning parameters via command-line:
$ ./sgfakeshm-connect-client --help
Usage:
sgfakeshm-connect-client [options]
Options:
--help or -h
--tcp <yes|no>
--ipc <yes|no>
--sharedmem <yes|no>
--socket-receive-nonblocking <yes|no>
--socket-receive-timeout-ms <int32>
--socket-send-nonblocking <yes|no>
--socket-send-timeout-ms <int32>
--socket-reconnect-time-min-ms <int32>
--socket-reconnect-time-max-ms <int32>
--worker-retry-interval-ms <uint64>
--heartbeat-interval-ms <uint64>
--liveness-timeout-ms <uint64>
--latency-smoothing-window-ms <uint64>
--throughput-smoothing-window-ms <uint64>
--shared-mem-heartbeat-block-size <uint32>
--shared-mem-liveness-timeout-ms <uint64>
It is however, much faster and easier to modify the configuration file instead of passing arguments to sgfakeshm-connect-client as it supports hot reloading.
The following symbols indicate:
- ✅: the specific transport is enabled.
- ❌: the specific transport is disabled.
- 🟢: the specific transport is connected and
./sgfakeshm-core-clientis prensent on the other side. - 🔴: the specific transport is disconnected and
./sgfakeshm-core-clientmight not be prensent on the other side.
sgfakeshm-core-client
sgfakeshm-core-client is the companion benchmarking application, which acts like your Unreal Engine or Unity plugin, and consists of two tabs. The first one is the Benchmark tab to verify the benchmarking latency and throughput from the second peer app, and the second one is the Tuning Info tab to verify if the sgfakeshm-connect-client-enforced optimizations have indeed been applied.
sgfakeshm-core-client supports the following keyboard shortcuts:
ESC,Q, orCtrl+Cto exit the application.Sto toggle between various predefined payload sizes, e.g.,1 KB,10 KB,100 KB,1 MB, and10 MB.Bto switch to theBenchmarktab.Tto switch to theTuning Infotab.
The following symbols indicate:
- ✅: the specific transport is enabled.
- ❌: the specific transport is disabled.
- 🟢: the specific transport is connected and
./sgfakeshm-connect-clientis prensent on the other side. - 🔴: the specific transport is disconnected and
./sgfakeshm-connect-clientmight not be prensent on the other side.
Important Benchmarking Limitation
The benchmarking utilities use the NNG Pair0 protocol for IPC and TCP transports.
Pair0 is intentionally designed as a one-to-one communication protocol, meaning that only one peer (one listener and one dialer) may exist and run at any given time.
Because of this limitation:
- Never run multiple instances of
sgfakeshm-connect-clientsimultaneously.
Likewise:
- Never run multiple instances of
sgfakeshm-core-clientsimultaneously.
Running multiple instances of either application at the same time will cause the benchmark applications to fail or crash because they attempt to establish multiple Pair0 connections.
So, this means at the time of benchmarking no instances of SenseCom or UE or Unity plugins should be running either.
The Configuration File
Depending on the platform SGFakeShm-dependant applications (such as SenseCom, UE plugin, or the benchmarking/tuning apps) are running on, all tuning parameters are generated or loaded from:
${XDG_CONFIG_HOME:-$HOME/.config}/SenseGlove/sgfakeshm-params.ymlon GNU/Linux, which typically equates to~/.config/SenseGlove/sgfakeshm-params.yml.%USERPROFILE%\Documents\SenseGlove\sgfakeshm-params.ymlon Microsoft Windows.
When SenseCom or sgfakeshm-connect-client start:
- If the file does not exist, it will automatically be generated.
- If the file exists and its version matches the currently supported version, its values override the built-in and hardcoded defaults.
- If the file format is not a valid YAML, or it contains invalid values, or the file version does not match a version that is shipped with the current
SGFakeShmversion, the existing file is preserved by renaming it tosgfakeshm-params.yml.YYYY-MM-DD-hh-mm-ss, and then a new configuration file containing the latest defaults is then generated automatically.
This approach allows users to preserve previous configurations while safely switching between various versions, whether old or new.
Hot Reloading
One particularly useful feature is that the configuration file supports hot reloading.
Whenever the file is saved:
- SenseCom automatically detects the changes.
- The configuration is reloaded.
- The new parameters take effect immediately.
Restarting SenseCom or applications using the SenseGlove libraries is therefore unnecessary.
This makes iterative tuning significantly easier.
Exposed Tuning Parameters
The generated sgfakeshm-params.yml file always contains generic documentation, along with a detailed explanation of every exposed tuning parameter and its default value. The following is the latest version of sgfakeshm-params.yml generated by the latest release of SGFakeShm at the time of writing:
# File name used for tweaking and tuning the FakeShm parameters.
# When this file does not exist it will be generated by the SGConnectShm upon
# initialization or reconfiguration and gets populated from the hardcoded values
# below.
# If it does indeed exist and file version matches the version supported by the
# current release of the SenseGlove libraries, the parameter values in this file
# will override the hardcoded values from the libraries.
# If the file has invalid values, or the version number does not match, it will
# be renamed to sgfakeshm-params.yml.YYYY-MM-DD-hh-mm-ss to
# preserve the user's chosen values and a new file will be generated containing
# the updated values or newly introduced parameters.
#
# NOTE: This file supports hot-reloading upon saving the file. Thus, you do
# not have to close SenseCom or plugin's relying on SenseGlove libraries in
# order to apply the changes. The changes will be picked up automatically
# as soon as a file change is detected.
# The current version of the the default tuning parameters configuration
# file.
#
# Existing tuning configuration files are only loaded when their version
# matches the version supported by the current FakeShm implementation.
# Otherwise, the existing file is backed up with a timestamped filename
# and a new file containing the current default parameters is generated.
#
# Please do not change this value if you want your changes to persist.
Version: 1
# If enabled, socket receive operations are performed in non-blocking
# mode.
# nng_recvmsg will return immediately if no message is available:
# - NNG_EAGAIN is returned instead of blocking
# This improves responsiveness but may increase CPU usage due to
# polling.
# When disabled, SocketReceiveTimeout controls blocking behavior.
SocketReceiveNonBlocking: true
# Receive timeout for the NNG socket in milliseconds.
# Controls how long nng_recvmsg blocks while waiting for a message.
# If no message is received within this interval, the call returns
# with a timeout, allowing the worker thread to wake up periodically
# to:
# - send heartbeats
# - detect peer liveness
# - respond to shutdown requests
# Lower values increase responsiveness but may slightly increase CPU
# usage.
# This only is taken into account when SocketReceiveNonBlocking is
# disabled.
SocketReceiveTimeout: 1
# If enabled, socket send operations are performed in non-blocking
# mode.
# nng_sendmsg will return immediately if the message cannot be sent:
# - NNG_EAGAIN is returned instead of blocking
# Useful for low-latency systems where blocking is undesirable.
SocketSendNonBlocking: false
# Send timeout for the NNG socket in milliseconds.
# Controls how long nng_sendmsg blocks while attempting to send a
# message.
# If the message cannot be sent within this interval, the call returns
# with a timeout error, allowing the system to avoid long blocking
# stalls.
# This only is taken into account when SocketSendNonBlocking is
# disabled.
SocketSendTimeout: 1
# This is the minimum amount of time (milliseconds) to wait before
# attempting to establish a connection after a previous attempt has
# failed. This can be set on a socket, but it can also be overridden
# on an individual dialer. The option is irrelevant for listeners.
SocketReconnectTimeMin: 1
# This is the maximum amount of time (milliseconds) to wait before
# attempting to establish a connection after a previous attempt has
# failed. If this is non-zero, then the time between successive
# connection attempts will start at the value of
# SocketReconnectTimeMin, and grow exponentially, until it reaches
# this value. If this value is zero, then no exponential back-off
# between connection attempts is done, and each attempt will wait the
# time specified by SocketReconnectTimeMin. This can be set on a
# socket, but it can also be overridden on an individual dialer. The
# option is irrelevant for listeners.
SocketReconnectTimeMax: 10
# FakeShm transport worker retry interval in milliseconds.
# Applied when:
# - no peer is connected
# - socket returns no data (timeout / EAGAIN)
# Prevents busy-waiting loops and reduces CPU usage while idle.
WorkerRetryInterval: 1
# FakeShm transport heartbeat interval in milliseconds.
# Determines how often heartbeat messages are sent to the peer to:
# - maintain connection activity
# - update last-seen timestamps
# Lower values improve liveness detection but increase traffic
# overhead.
HeartbeatInterval: 1
# FakeShm IPC and TCP transports liveness timeout in milliseconds.
# Defines how long a peer can remain silent before being considered
# dead.
# Compared against the timestamp of the last received message.
# If exceeded, the peer is treated as disconnected/unresponsive.
LivenessTimeout: 5
# Latency smoothing window in milliseconds.
# Defines the time range over which latency samples are accumulated
# to compute a rolling average (smoothed latency).
# Larger values produce more stable results but react slower to
# changes.
LatencySmoothingWindow: 1000
# Throughput smoothing window in milliseconds.
# Defines the time range over which throughput snapshots are
# accumulated to compute a rolling average (smoothed snapshots).
# Larger values produce more stable results but react slower to
# changes.
ThroughputSmoothingWindow: 1000
# The legacy Boost SharedMem heartbeat block size.
SharedMemHeartbeatBlockSize: 1024
# FakeShm SharedMem liveness timeout in milliseconds.
# Defines how long a peer can remain silent before being considered
# dead.
# Compared against the timestamp of the last received message.
# If exceeded, the peer is treated as disconnected/unresponsive.
SharedMemLivenessTimeout: 50