From 1e99a6993a367056e43d35e877dc993ee8733766 Mon Sep 17 00:00:00 2001 From: cjsha Date: Wed, 27 Aug 2025 00:16:48 -0400 Subject: [PATCH 01/11] 1st draft tutorial for tuning ReadSize Also: - Add references to this tutorial throughout other articles - Add workflows for the LoadTester operators --- .../getting-started/onix-configuration.md | 3 +- articles/tutorials/toc.yml | 1 + articles/tutorials/tune-readsize.md | 213 ++++++++++++++++++ .../tune-readsize/histogram1d_1024.webp | Bin 0 -> 12424 bytes .../tune-readsize/histogram1d_16384.webp | Bin 0 -> 17462 bytes .../tune-readsize/histogram1d_2048.webp | Bin 0 -> 13598 bytes .../tune-readsize/percent-used_1024.webp | Bin 0 -> 12248 bytes .../tune-readsize/percent-used_16384.webp | Bin 0 -> 12508 bytes .../tune-readsize/percent-used_2048.webp | Bin 0 -> 21128 bytes src/bonsai-onix1 | 2 +- .../hardware/configuration.tmpl.partial | 6 +- .../operators/ConfigureLoadTester.bonsai | 7 +- workflows/operators/LoadTesterData.bonsai | 29 +++ workflows/operators/LoadTesterLoopback.bonsai | 31 +++ .../tune-readsize/configuration.bonsai | 103 +++++++++ .../tutorials/tune-readsize/loadtester.bonsai | 92 ++++++++ .../tune-readsize/memory-monitor.bonsai | 21 ++ .../tune-readsize/tune-readsize.bonsai | 192 ++++++++++++++++ 18 files changed, 692 insertions(+), 8 deletions(-) create mode 100644 articles/tutorials/tune-readsize.md create mode 100644 images/tutorials/tune-readsize/histogram1d_1024.webp create mode 100644 images/tutorials/tune-readsize/histogram1d_16384.webp create mode 100644 images/tutorials/tune-readsize/histogram1d_2048.webp create mode 100644 images/tutorials/tune-readsize/percent-used_1024.webp create mode 100644 images/tutorials/tune-readsize/percent-used_16384.webp create mode 100644 images/tutorials/tune-readsize/percent-used_2048.webp create mode 100644 workflows/operators/LoadTesterData.bonsai create mode 100644 workflows/operators/LoadTesterLoopback.bonsai create mode 100644 workflows/tutorials/tune-readsize/configuration.bonsai create mode 100644 workflows/tutorials/tune-readsize/loadtester.bonsai create mode 100644 workflows/tutorials/tune-readsize/memory-monitor.bonsai create mode 100644 workflows/tutorials/tune-readsize/tune-readsize.bonsai diff --git a/articles/getting-started/onix-configuration.md b/articles/getting-started/onix-configuration.md index fbf61ba8..84c02add 100644 --- a/articles/getting-started/onix-configuration.md +++ b/articles/getting-started/onix-configuration.md @@ -54,7 +54,8 @@ The data acquisition process is started when ContextTask passes through . StartAcquisition allows the user to set parameters that are related to data acquisition such as ReadSize and WriteSize. Setting the ReadSize property for a particular workflow is a balancing act of minimizing latency of data data transfers from the ONIX -system and avoiding data accumulation in the ONIX system's hardware buffer. +system and avoiding data accumulation in the ONIX system's hardware buffer. To learn about the +process of tuning ReadSize, check out the tutorial. ::: workflow ![/workflows/getting-started/start-acquisition.bonsai workflow](../../workflows/getting-started/start-acquisition.bonsai) diff --git a/articles/tutorials/toc.yml b/articles/tutorials/toc.yml index f91f9f11..977e7143 100644 --- a/articles/tutorials/toc.yml +++ b/articles/tutorials/toc.yml @@ -2,3 +2,4 @@ items: - href: ephys-processing-listening.md - href: ephys-socket.md + - href: tune-readsize.md diff --git a/articles/tutorials/tune-readsize.md b/articles/tutorials/tune-readsize.md new file mode 100644 index 00000000..e816d71e --- /dev/null +++ b/articles/tutorials/tune-readsize.md @@ -0,0 +1,213 @@ +--- +uid: tune-readsize +title: Tune ReadSize +--- + +This tutorial shows how to tune 's + property to avoid buffer overflow errors which +prematurely terminates the acquisition session and minimize latency of data transfer between the +ONIX system and the computer for low-latency closed-loop feedback. + +## ONIX Hardware Buffer and ReadSize + +An important concept for understanding the effect of ReadSize is the hardware buffer. The hardware +buffer is a temporary storage area that facilitates data transfer between the ONIX system and the +PC. When the hardware buffer accumulates an amount of data that exceeds a threshold, this chunk of +data is read by the PC and removed from the buffer. This threshold is determined by the value of +ReadSize, a property of the StartAcquisition operator which is necessary for every workflow that +uses to acquire data from ONIX. + +### ReadSize Tradeoffs + +There are two primary tradeoffs when selecting the optimal ReadSize value: latency and risk of +hardware buffer overflow. Let's take at look at how those are affected by tuning ReadSize lower or +higher for a given data rate. + +As ReadSize decreases, less data in the buffer is required for the computer to be able to read from +the buffer. This means less time would need to pass before having access to that data. Therefore, +setting ReadSize lower provides lower latency data (i.e. allows access to data closer in time to the +physical creation of that data). However, there is a limit to this. Each call to the function that +reads data from the hardware buffer requires resources from the computer (i.e. memory and CPU +cycles). If ReadSize is too low such that the read function is being called in succession too +rapidly, your computer won't be able to keep up with the amount of read function calls required to +read all the data from the buffer. This can lead to an over-accumulation of data in the hardware +buffer and an error when the buffer reaches maximum capacity that terminates the acquisition +session. + +As ReadSize increases, more data in the buffer is required for the computer to be able to read from +the buffer. This means more time would need to pass before having access to that data. Therefore, +setting ReadSize higher reduces the frequency of calls to the read function thereby reducing the +risk that your computer is overwhelmed by the amount of read functions calls required to clear the +buffer. As you might have surmised already, this increases the latency between the creation of data +and the retrieval of that data by your computer. + +## Tuning ReadSize + +### Setup + +Follow the [Getting Started](xref:getting-started) guide to set up your Bonsai environment and +familiarize yourself with using OpenEphys.Onix1 to acquire data from ONIX. Copy the following +workflow into the Bonsai workflow editor by hovering over workflow image and clicking on the +clipboard icon that appears. + +::: workflow +![SVG of load tester workflow](../../workflows/tutorials/tune-readsize/tune-readsize.bonsai) +::: + +Open Bonsai and paste this workflow by clicking the Bonsai workflow editor pane and hitting +Ctrl+V. + +### Workflow Description + +::: workflow +![SVG of load tester workflow configuration chain](../../workflows/tutorials/tune-readsize/configuration.bonsai) +::: + +The top-level configuration chain includes a . The load +tester device allows us to emulate different rates of data production and measure latency between +data reads and data writes. For example, enabling two Neuropixels 2.0 probes will produce about 47 +MB/s ≈((8\*2+384\*2)\*30000\*2)/1e6. In this example, we'll use `ConfigureLoadTester` to emulate +this payload. To do so, `ConfigureLoadTester`'s ReceivedWords and FramesPerSecond are respectively +392 and 60,000. This parallels the rate of data being produced by two probes: 1 + at 60 kHz. The Enable property is set to True to +enable the LoadTester device. Its DeviceName is set to "Load Tester" so that it has a +straightforward name to use to link the and + operators. The DeviceAddress property is set to 11 because +that's how this device is indexed in the ONIX system. + + +All of the 's devices except the MemoryMonitor are +disabled. + +'s is set +to 16384. This defines a readily-available pool of memory for the creation of output data frames. A +larger size will reduce the frequency of dynamic memory allocation system calls but increase the +expense of each of those calls. The effect on real-time performance is typically not as large as +that of the ReadSize property because it does not determine when they are written to hardware. Data +is written to hardware as soon as an output frame has been created. In contrast, data is read from +hardware whenever more than ReadSize bytes have accumulated in the input buffer. The ReadSize +property is also set to 16384. We'll take a closer look at and play with that value in the next +section. + +::: workflow +![SVG of load tester workflow loadtester branch](../../workflows/tutorials/tune-readsize/loadtester.bonsai) +::: + +LoadTesterData produces a sequence of +[LoadTesterDataFrames](xref:OpenEphys.Onix1.LoadTesterDataFrame). The + member and the + member are each selected from the +LoadTesterDataFrame with their own . + +The HubClock member indicates the value of the hub's clock when that LoadTesterDataFrame was +produced. A hub is a piece of hardware that coordinates a group of devices e.g. the breakout board +is a hub that coordinates DigitalInput, DigitalOutput, AnalogIO, Memory Monitor, etc.. EveryNth is a + which only allows through every Nth element in the observable +sequence. You can inspect its logic by double-clicking the node when the workflow is not running. In +this case, the N property is set to 100, so every 100th sample is allowed through the EveryNth +operator and sent to LoadTesterLoopback. This operator is a *sink* operator which writes the +HubClock member that was passed through the EveryNth operator back to the load tester device. The +load tester device will then update the HubClockDelta members in all subsequent +LoadTesterDataFrames. + + +The HubClockDelta member indicates the difference between the HubClock value sent to the +LoadTesterLoopback operator and the load tester's hub clock value when that HubClock value was +received by the hardware. filters out repeated elements +which is necessary because HubClockDelta only ends up getting updated every 100th +LoadTesterDataFrame. The next operator +converts the HubClockDelta from units of Hub clock cycles to units of microseconds. This data gets +sent to to help visualize the distribution of closed-loop latencies. + +::: workflow +![SVG of load tester workflow memorymonitor branch](../../workflows/tutorials/tune-readsize/memory-monitor.bonsai) +::: + +To learn about the branch, visit the [Breakout Board Memory +Monitor](xref:breakout_memory-monitor) (or the equivalent for any of our other hardware) page. + +### Measuring Latency at Different ReadSize Values + +#### ReadSize = 16384 + +With ReadSize set to 16384, start the workflow, and [open the visualizers](xref:visualize-data) for +the PercentUsed and Histogram1D nodes: + +![screenshot of Histogram1D visualizers with ReadSize 16384](../../images/tutorials/tune-readsize/histogram1d_16384.webp) +![screenshot of PercentUsed visualizers with ReadSize 16384](../../images/tutorials/tune-readsize/percent-used_16384.webp) + +Average latency appears to be about 300 μs (in this plot, 1000 corresponds to 1 ms). This +approximately comports with expectations. If data is being produced at about 47MB/s, it takes about +348 μs to accumulate 16384 bytes. This isn't a perfect estimate because there are other devices +producing data (e.g. the Memory Monitor and Heartbeat) though the data rate of those devices is +completely dwarfed by the data rate of pay load tester. The most likely source of this discrepancy +is that the computer is not 100% available to perform the read operation. This causes some reads to +be delayed and some reads to happen sooner. This calculation that leads to a 348 μs latency can be a +first order estimate of latency to determine an optimal ReadSize, but it's not perfect. The PayLoad +tester provides empirical measurements of latency and memory usage. + +The hardware buffer also doesn't seem to be over-accumulating data i.e. the MemoryMonitor +PercentUsed visualizer shows that the percentage of the buffer being used remains close to zero. + +For many experiments, the above latency is totally acceptable. In any case, let's see how much lower +we can get the latency for more intense closed-loop experiments. + +#### ReadSize = 2048 + +Set ReadSize to 2048 and restart the workflow (ReadSize is a +[](xref:OpenEphys.Onix1#configuration) +property so it only updates when a workflow starts), and open the same visualizers: + +![screenshot of Histogram1D visualizers with ReadSize 2048](../../images/tutorials/tune-readsize/histogram1d_2048.webp) +![screenshot of PercentUsed visualizers with ReadSize 2048](../../images/tutorials/tune-readsize/percent-used_2048.webp) + +The closed-loop latencies now average about 80 μs. The hardware buffer still seems pretty stable +around zero even after letting some time pass. Let's see if we can decrease latency even further +without overflowing the buffer. + +#### ReadSize = 1024 + +Set ReadSize to 1024, restart the workflow, and open the same visualizers. + +![screenshot of Histogram1D visualizers with ReadSize 1024](../../images/tutorials/tune-readsize/histogram1d_1024.webp) +![screenshot of PercentUsed visualizers with ReadSize 1024](../../images/tutorials/tune-readsize/percent-used_1024.webp) + +The Histogram1D visualizer appears to be empty. This is because the latency immediately exceeds the +upper limit x-axis of 1 ms. You can see this by inspecting the visualizer for the node prior to +Histogram1D. Because the computer cannot keep up with the amount of read operations necessary to +clear the buffer, there is a bunch of data in the queue that needs to be read before the most recent +data frames are accessible. Therefore, by the time a particular data frame gets read from the +buffer, a bunch of time has already passed since that frame was generated. This means it takes +longer for a given HubClock value to reach the LoadTesterLoopBack operator which subsequently means +increased latencies. + +Because the amount of data in the hardware buffer is rising (which can be seen by looking at the +MemoryMonitor PercentUsed visualizer), the acquisition session will eventually terminate in an error +when the MemoryMonitor PercentUsed reaches 100% and the hardware buffer overflows. + +> [!NOTE] +> The point at which your computer will not be able to keep up with with the number of reads to keep +> the buffer clear as demonstrated here depends on your computer's capabilities and might be +> different from when our computer can no longer do that. The computer used to create this tutorial +> has the following specs: +> - CPU: Intel i9-12900K +> - RAM: 64 GB +> - GPU: NVIDIA GTX 1070 8GB +> - OS: Windows 11 + +#### Summary + +The results of our experimentation are as follows: + +| ReadSize | Latency | Buffer Usage | Notes | +|----------|----------------------|-----------------|----------------------------------------------------------------------------------------------------| +| 16384 | ~300 μs | Stable at 0% | Perfectly fine if there aren't any strict low latency requirements, lowest risk of buffer overflow | +| 2048 | ~80 μs | Stable near 0% | Balances latency requirements with low risk of buffer overflow | +| 1024 | Rises steadily | Rises untenably | Certain buffer overflow error | + +These results may differ for your experimental system. For example, your system might have different +bandwidth requirements (if you are using different devices, data is produced at a different rate) or +use a computer with different performance capabilities (which changes how quickly it can perform +read operations). + + \ No newline at end of file diff --git a/images/tutorials/tune-readsize/histogram1d_1024.webp b/images/tutorials/tune-readsize/histogram1d_1024.webp new file mode 100644 index 0000000000000000000000000000000000000000..bb975f2e4ed3a388b04bab5748b6aa1bc2efbbf0 GIT binary patch literal 12424 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∾F8$rJ2UHo6^Ex1CIzo>+8Y8Dv}e%zj`VJV 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 literal 0 HcmV?d00001 diff --git a/images/tutorials/tune-readsize/histogram1d_16384.webp b/images/tutorials/tune-readsize/histogram1d_16384.webp new file mode 100644 index 0000000000000000000000000000000000000000..259e3e7fb78de7f1db037229bccdefa87823c69b GIT binary patch literal 17462 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 E1Mcf>Q2+n{ literal 0 HcmV?d00001 diff --git a/images/tutorials/tune-readsize/histogram1d_2048.webp b/images/tutorials/tune-readsize/histogram1d_2048.webp new file mode 100644 index 0000000000000000000000000000000000000000..93db118a77ff2f1777815db568b3f3866329b2c3 GIT binary patch literal 13598 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 M0arOb;Kt=Y0H>3(;{X5v literal 0 HcmV?d00001 diff --git a/images/tutorials/tune-readsize/percent-used_1024.webp b/images/tutorials/tune-readsize/percent-used_1024.webp new file mode 100644 index 0000000000000000000000000000000000000000..f70338ce2d4b4b77905267cb88aad2615c738d16 GIT binary patch literal 12248 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 literal 0 HcmV?d00001 diff --git a/images/tutorials/tune-readsize/percent-used_16384.webp b/images/tutorials/tune-readsize/percent-used_16384.webp new file mode 100644 index 0000000000000000000000000000000000000000..5effe5e035e6ce4a922d245232baef16608fe731 GIT binary patch literal 12508 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 CU4)ka literal 0 HcmV?d00001 diff --git a/images/tutorials/tune-readsize/percent-used_2048.webp b/images/tutorials/tune-readsize/percent-used_2048.webp new file mode 100644 index 0000000000000000000000000000000000000000..62310020593e1d36a91915b7edb3f95b31dbba51 GIT binary patch literal 21128 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 qZQq0FojGTune ReadSize tutorial.

diff --git a/workflows/operators/ConfigureLoadTester.bonsai b/workflows/operators/ConfigureLoadTester.bonsai index fc4b0bc8..eb26764b 100644 --- a/workflows/operators/ConfigureLoadTester.bonsai +++ b/workflows/operators/ConfigureLoadTester.bonsai @@ -1,5 +1,5 @@  - @@ -13,12 +13,11 @@ - LoadTester 0 - true + false 0 0 - 1000 + 0 diff --git a/workflows/operators/LoadTesterData.bonsai b/workflows/operators/LoadTesterData.bonsai new file mode 100644 index 00000000..b11c6561 --- /dev/null +++ b/workflows/operators/LoadTesterData.bonsai @@ -0,0 +1,29 @@ + + + + + + + Load Tester + + + + HubClock + + + HubClockDelta + + + Counter + + + + + + + + + \ No newline at end of file diff --git a/workflows/operators/LoadTesterLoopback.bonsai b/workflows/operators/LoadTesterLoopback.bonsai new file mode 100644 index 00000000..86fe5630 --- /dev/null +++ b/workflows/operators/LoadTesterLoopback.bonsai @@ -0,0 +1,31 @@ + + + + + + + Load Tester + + + + HubClock + + + + Load Tester + + + + HubClockDelta + + + + + + + + + \ No newline at end of file diff --git a/workflows/tutorials/tune-readsize/configuration.bonsai b/workflows/tutorials/tune-readsize/configuration.bonsai new file mode 100644 index 00000000..bbfbabc6 --- /dev/null +++ b/workflows/tutorials/tune-readsize/configuration.bonsai @@ -0,0 +1,103 @@ + + + + + + + riffa + 0 + + + + + Load Tester + 11 + true + 240 + 100 + 100000 + + + + + BreakoutBoard + + BreakoutBoard/PersistentHeartbeat + 0 + 100 + + + BreakoutBoard/AnalogIO + 6 + false + TenVolts + TenVolts + TenVolts + TenVolts + TenVolts + TenVolts + TenVolts + TenVolts + TenVolts + TenVolts + TenVolts + TenVolts + Input + Input + Input + Input + Input + Input + Input + Input + Input + Input + Input + Input + + + BreakoutBoard/DigitalIO + 7 + false + 0 + + + + BreakoutBoard/OutputClock + 5 + false + 1000000 + 50 + 0 + + + BreakoutBoard/HarpSyncInput + 12 + false + Breakout + + + BreakoutBoard/MemoryMonitor + 10 + true + 100 + + + + + + 16384 + 16384 + + + + + + + + + + \ No newline at end of file diff --git a/workflows/tutorials/tune-readsize/loadtester.bonsai b/workflows/tutorials/tune-readsize/loadtester.bonsai new file mode 100644 index 00000000..f2b6825a --- /dev/null +++ b/workflows/tutorials/tune-readsize/loadtester.bonsai @@ -0,0 +1,92 @@ + + + + + + + Load Tester + + + + HubClock + + + Every Nth + + + + Source1 + + + + + + Index + + + + + + + 100 + + + + + 0 + + + + + + + + + + + + + + + + + Load Tester + + + + HubClockDelta + + + + + + ToMilliseconds + it/250000.0 + + + + 0 + 1 + 1000 + false + true + + + + + + + + + + + + + + \ No newline at end of file diff --git a/workflows/tutorials/tune-readsize/memory-monitor.bonsai b/workflows/tutorials/tune-readsize/memory-monitor.bonsai new file mode 100644 index 00000000..7e2cccd7 --- /dev/null +++ b/workflows/tutorials/tune-readsize/memory-monitor.bonsai @@ -0,0 +1,21 @@ + + + + + + + BreakoutBoard/MemoryMonitor + + + + PercentUsed + + + + + + + \ No newline at end of file diff --git a/workflows/tutorials/tune-readsize/tune-readsize.bonsai b/workflows/tutorials/tune-readsize/tune-readsize.bonsai new file mode 100644 index 00000000..792e1f17 --- /dev/null +++ b/workflows/tutorials/tune-readsize/tune-readsize.bonsai @@ -0,0 +1,192 @@ + + + + + + + riffa + 0 + + + + + Load Tester + 11 + true + 240 + 100 + 100000 + + + + + BreakoutBoard + + BreakoutBoard/PersistentHeartbeat + 0 + 100 + + + BreakoutBoard/AnalogIO + 6 + false + TenVolts + TenVolts + TenVolts + TenVolts + TenVolts + TenVolts + TenVolts + TenVolts + TenVolts + TenVolts + TenVolts + TenVolts + Input + Input + Input + Input + Input + Input + Input + Input + Input + Input + Input + Input + + + BreakoutBoard/DigitalIO + 7 + false + 0 + + + + BreakoutBoard/OutputClock + 5 + false + 1000000 + 50 + 0 + + + BreakoutBoard/HarpSyncInput + 12 + false + Breakout + + + BreakoutBoard/MemoryMonitor + 10 + true + 100 + + + + + + 16384 + 16384 + + + + + Load Tester + + + + HubClock + + + Every Nth + + + + Source1 + + + + + + Index + + + + + + + 100 + + + + + 0 + + + + + + + + + + + + + + + + + Load Tester + + + + HubClockDelta + + + + + + ToMilliseconds + it/250000.0 + + + + 0 + 1 + 1000 + false + true + + + + + BreakoutBoard/MemoryMonitor + + + + PercentUsed + + + + + + + + + + + + + + + + + \ No newline at end of file From f827ddacf8ddbc8b6e8e1a609b0801ab337dda95 Mon Sep 17 00:00:00 2001 From: cjsha Date: Tue, 2 Sep 2025 09:44:28 -0400 Subject: [PATCH 02/11] Change properties in workflow to match content of article --- workflows/tutorials/tune-readsize/configuration.bonsai | 4 ++-- workflows/tutorials/tune-readsize/tune-readsize.bonsai | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/workflows/tutorials/tune-readsize/configuration.bonsai b/workflows/tutorials/tune-readsize/configuration.bonsai index bbfbabc6..551b168d 100644 --- a/workflows/tutorials/tune-readsize/configuration.bonsai +++ b/workflows/tutorials/tune-readsize/configuration.bonsai @@ -16,9 +16,9 @@ Load Tester 11 true - 240 + 392 100 - 100000 + 60000 diff --git a/workflows/tutorials/tune-readsize/tune-readsize.bonsai b/workflows/tutorials/tune-readsize/tune-readsize.bonsai index 792e1f17..01fb85b8 100644 --- a/workflows/tutorials/tune-readsize/tune-readsize.bonsai +++ b/workflows/tutorials/tune-readsize/tune-readsize.bonsai @@ -19,9 +19,9 @@ Load Tester 11 true - 240 + 392 100 - 100000 + 60000 From fd6a2f838c443ddfe299f5b414c43f1e55faa74d Mon Sep 17 00:00:00 2001 From: jonnew Date: Fri, 5 Sep 2025 17:16:32 -0400 Subject: [PATCH 03/11] Edit the tune-readsize tutorial - Lots of edits to the text - Will need a lot of review --- articles/tutorials/tune-readsize.md | 435 ++++++++++++++++------------ 1 file changed, 255 insertions(+), 180 deletions(-) diff --git a/articles/tutorials/tune-readsize.md b/articles/tutorials/tune-readsize.md index e816d71e..17294acf 100644 --- a/articles/tutorials/tune-readsize.md +++ b/articles/tutorials/tune-readsize.md @@ -1,213 +1,288 @@ --- uid: tune-readsize -title: Tune ReadSize +title: Optimizing Closed Loop Performance --- -This tutorial shows how to tune 's - property to avoid buffer overflow errors which -prematurely terminates the acquisition session and minimize latency of data transfer between the -ONIX system and the computer for low-latency closed-loop feedback. - -## ONIX Hardware Buffer and ReadSize - -An important concept for understanding the effect of ReadSize is the hardware buffer. The hardware -buffer is a temporary storage area that facilitates data transfer between the ONIX system and the -PC. When the hardware buffer accumulates an amount of data that exceeds a threshold, this chunk of -data is read by the PC and removed from the buffer. This threshold is determined by the value of -ReadSize, a property of the StartAcquisition operator which is necessary for every workflow that -uses to acquire data from ONIX. - -### ReadSize Tradeoffs - -There are two primary tradeoffs when selecting the optimal ReadSize value: latency and risk of -hardware buffer overflow. Let's take at look at how those are affected by tuning ReadSize lower or -higher for a given data rate. - -As ReadSize decreases, less data in the buffer is required for the computer to be able to read from -the buffer. This means less time would need to pass before having access to that data. Therefore, -setting ReadSize lower provides lower latency data (i.e. allows access to data closer in time to the -physical creation of that data). However, there is a limit to this. Each call to the function that -reads data from the hardware buffer requires resources from the computer (i.e. memory and CPU -cycles). If ReadSize is too low such that the read function is being called in succession too -rapidly, your computer won't be able to keep up with the amount of read function calls required to -read all the data from the buffer. This can lead to an over-accumulation of data in the hardware -buffer and an error when the buffer reaches maximum capacity that terminates the acquisition -session. - -As ReadSize increases, more data in the buffer is required for the computer to be able to read from -the buffer. This means more time would need to pass before having access to that data. Therefore, -setting ReadSize higher reduces the frequency of calls to the read function thereby reducing the -risk that your computer is overwhelmed by the amount of read functions calls required to clear the -buffer. As you might have surmised already, this increases the latency between the creation of data -and the retrieval of that data by your computer. - -## Tuning ReadSize - -### Setup - -Follow the [Getting Started](xref:getting-started) guide to set up your Bonsai environment and -familiarize yourself with using OpenEphys.Onix1 to acquire data from ONIX. Copy the following -workflow into the Bonsai workflow editor by hovering over workflow image and clicking on the -clipboard icon that appears. - -::: workflow -![SVG of load tester workflow](../../workflows/tutorials/tune-readsize/tune-readsize.bonsai) -::: - -Open Bonsai and paste this workflow by clicking the Bonsai workflow editor pane and hitting -Ctrl+V. +This tutorial shows how to optimize the +'s + property for your specific data +acquisition setup to minimize delays between data collection and computer +processing. This tutorial provide a method to tune `ReadSize` within the context +of your particular data sources and computer specifications in order to achieve +the fastest possible response times for closed-loop experiments. In most +situations, sub-200 microsecond closed-loop response times can be achieved. -### Workflow Description +> [!NOTE] +> Performance will vary based on your computer's capabilities and your results +> might differ those presented below. The computer used to create this tutorial +> has the following specs: +> - CPU: Intel i9-12900K +> - RAM: 64 GB +> - GPU: NVIDIA GTX 1070 8GB +> - OS: Windows 11 -::: workflow -![SVG of load tester workflow configuration chain](../../workflows/tutorials/tune-readsize/configuration.bonsai) -::: +## Hardware Buffer and ReadSize + +The ONIX **Hardware Buffer** consists of 2GB of dedicated RAM +that belongs to the acquisition hardware (it is _not_ RAM in the host computer). +The hardware buffer temporarily stores data that has not yet been transferred to +the host. When the host software is consuming data optimally, the hardware +buffer is bypassed entirely and data flows directly from production to the +host RAM, minimizing the latency between data collection and processing. + +Each time the host software reads data from the hardware, it obtains +**ReadSize** bytes of data using the following procedure: + +1. A block of memory that is `ReadSize` bytes long is allocated by the API +2. A pointer to that memory is provided to the kernel driver, which locks it + into kernel mode and initiates a [DMA + transfer](https://en.wikipedia.org/wiki/Direct_memory_access) from the + hardware. +3. The transfer is performed by the ONIX hardware without CPU intervention and + completes once `ReadSize` bytes have been produced. +4. Upon transfer completion, the buffer is passed back to user mode and the API + function returns with a pointer to the filled buffer. + +There are a couple of things to note about this process: + +1. Memory is allocated only once by the API, and the transfer is + [zero-copy](https://en.wikipedia.org/wiki/Zero-copy). ONIX hardware writes + directly into the API-allocated buffer autonomously without using the host + computer's resources. Within this process, `ReadSize` determines the amount + of data that is transferred each time the API reads data from the hardware. +2. If the buffer is allocated and the transfer initiated by the host API before + data is produced by the hardware, the data is transferred directly into the + buffer and completely bypasses the Hardware Buffer. In this case, hardware is + literally streaming data to the software buffer _the moment it is produced_. + It is physically impossible to achieve lower latencies than this situation. + The goal of this tutorial is to allow your system to operate in this regime. + +The size of hardware to host data transfers is determined by the + property of the +StartAcquisition operator, which is necessary for every workflow that uses + to acquire data from ONIX. Choosing an optimal `ReadSize` +value balances the tradeoff between latency and overall bandwidth. Smaller +`ReadSize` values mean that less data needs to accumulate before the kernel +driver relinquishes control of the buffer to software. This, in effect, means +less time needs to pass before software can start operating on data, and thus +lower-latency feedback loops can be achieved. However, because each transfer +requires calls to the kernel driver, they incur significant overhead. If +`ReadSize` is so low that the average time it takes to perform a data transfer +is longer than the time it takes the hardware to produce data, data will +accumulate in the Hardware Buffer. This will destroy real-time performance and +eventually cause the hardware buffer to overflow, terminating acquisition. + +## Tuning ReadSize to Optimize Closed Loop Performance +ONIX provides a mechanism for tuning the value of `ReadSize` to optimize closed +loop performance that takes into account the indosycncracies of your host +computer and experimental acquisition setup. -The top-level configuration chain includes a . The load -tester device allows us to emulate different rates of data production and measure latency between -data reads and data writes. For example, enabling two Neuropixels 2.0 probes will produce about 47 -MB/s ≈((8\*2+384\*2)\*30000\*2)/1e6. In this example, we'll use `ConfigureLoadTester` to emulate -this payload. To do so, `ConfigureLoadTester`'s ReceivedWords and FramesPerSecond are respectively -392 and 60,000. This parallels the rate of data being produced by two probes: 1 - at 60 kHz. The Enable property is set to True to -enable the LoadTester device. Its DeviceName is set to "Load Tester" so that it has a -straightforward name to use to link the and - operators. The DeviceAddress property is set to 11 because -that's how this device is indexed in the ONIX system. - - -All of the 's devices except the MemoryMonitor are -disabled. - -'s is set -to 16384. This defines a readily-available pool of memory for the creation of output data frames. A -larger size will reduce the frequency of dynamic memory allocation system calls but increase the -expense of each of those calls. The effect on real-time performance is typically not as large as -that of the ReadSize property because it does not determine when they are written to hardware. Data -is written to hardware as soon as an output frame has been created. In contrast, data is read from -hardware whenever more than ReadSize bytes have accumulated in the input buffer. The ReadSize -property is also set to 16384. We'll take a closer look at and play with that value in the next -section. - -::: workflow -![SVG of load tester workflow loadtester branch](../../workflows/tutorials/tune-readsize/loadtester.bonsai) -::: +> [!NOTE] +> If you are not familiar with the basic usage of the `OpenEphys.Onix1` library, +> then visit the [Getting Started](xref:getting-started) guide to set up your +> Bonsai environment and familiarize yourself with using the library to acquire +> data from ONIX before proceeding. + +Copy the following workflow into the Bonsai workflow editor by hovering over +workflow image and clicking on the clipboard icon that appears. Open Bonsai and +paste this workflow by clicking the Bonsai workflow editor pane and hitting +Ctrl+V. -LoadTesterData produces a sequence of -[LoadTesterDataFrames](xref:OpenEphys.Onix1.LoadTesterDataFrame). The - member and the - member are each selected from the -LoadTesterDataFrame with their own . - -The HubClock member indicates the value of the hub's clock when that LoadTesterDataFrame was -produced. A hub is a piece of hardware that coordinates a group of devices e.g. the breakout board -is a hub that coordinates DigitalInput, DigitalOutput, AnalogIO, Memory Monitor, etc.. EveryNth is a - which only allows through every Nth element in the observable -sequence. You can inspect its logic by double-clicking the node when the workflow is not running. In -this case, the N property is set to 100, so every 100th sample is allowed through the EveryNth -operator and sent to LoadTesterLoopback. This operator is a *sink* operator which writes the -HubClock member that was passed through the EveryNth operator back to the load tester device. The -load tester device will then update the HubClockDelta members in all subsequent -LoadTesterDataFrames. - - -The HubClockDelta member indicates the difference between the HubClock value sent to the -LoadTesterLoopback operator and the load tester's hub clock value when that HubClock value was -received by the hardware. filters out repeated elements -which is necessary because HubClockDelta only ends up getting updated every 100th -LoadTesterDataFrame. The next operator -converts the HubClockDelta from units of Hub clock cycles to units of microseconds. This data gets -sent to to help visualize the distribution of closed-loop latencies. - -::: workflow -![SVG of load tester workflow memorymonitor branch](../../workflows/tutorials/tune-readsize/memory-monitor.bonsai) +::: workflow +![SVG of load tester workflow](../../workflows/tutorials/tune-readsize/tune-readsize.bonsai) ::: -To learn about the branch, visit the [Breakout Board Memory -Monitor](xref:breakout_memory-monitor) (or the equivalent for any of our other hardware) page. - -### Measuring Latency at Different ReadSize Values -#### ReadSize = 16384 -With ReadSize set to 16384, start the workflow, and [open the visualizers](xref:visualize-data) for -the PercentUsed and Histogram1D nodes: +### Hardware Configuration +The top-row configuration chain includes a + operator. This configures ONIX's Load +Tester Device, which produces and consumes data at user specified rates for +testing and tuning the latency between data production and real-time feedback. +This device is _not a emulator_. It is a real hardware device that produces and +consumes data using the selected driver and physical link (e.g. PCIe bus) and +thus provides accurate measurements of feedback performance for a given host +computer. -![screenshot of Histogram1D visualizers with ReadSize 16384](../../images/tutorials/tune-readsize/histogram1d_16384.webp) -![screenshot of PercentUsed visualizers with ReadSize 16384](../../images/tutorials/tune-readsize/percent-used_16384.webp) - -Average latency appears to be about 300 μs (in this plot, 1000 corresponds to 1 ms). This -approximately comports with expectations. If data is being produced at about 47MB/s, it takes about -348 μs to accumulate 16384 bytes. This isn't a perfect estimate because there are other devices -producing data (e.g. the Memory Monitor and Heartbeat) though the data rate of those devices is -completely dwarfed by the data rate of pay load tester. The most likely source of this discrepancy -is that the computer is not 100% available to perform the read operation. This causes some reads to -be delayed and some reads to happen sooner. This calculation that leads to a 348 μs latency can be a -first order estimate of latency to determine an optimal ReadSize, but it's not perfect. The PayLoad -tester provides empirical measurements of latency and memory usage. +::: workflow +![SVG of load tester workflow configuration chain](../../workflows/tutorials/tune-readsize/configuration.bonsai) +::: -The hardware buffer also doesn't seem to be over-accumulating data i.e. the MemoryMonitor -PercentUsed visualizer shows that the percentage of the buffer being used remains close to zero. +We need to configure the load tester to produce and consume the same amount of +data as our real experimental hardware would. For example, lets say that during +our closed loop experiment, feedback signals will be generated as a function of +data acquired from two Neuropixels 2.0 probes, each of which generates a 384 +channel sample at 30 kHz. The overall bandwidth is + +$$ +\begin{equation} + 2\,probes*\frac{384\,chan.}{probe}*\frac{30\,ksamp.}{sec\,chan.}*\frac{2\,bytes}{samp.} \approx 47\,MB/s + \label{eq:2xnpx2bw} +\end{equation} +$$ + +We'll setup `ConfigureLoadTester` to produce data at the same frequency and +bandwidth as two Neuropixels 2.0 probes with the following settings: + +- `DeviceAddress` is set to 11 because that's how this device is indexed in the + ONIX system. +- `DeviceName` is set to "LoadTester" +- `Enable`is set to True to enable the LoadTester device. +- `FramesPerSecond` is then set to 60,000 Hz. The rate at which frames are + produced by two probes. +- `ReceivedWords` is set to 392 bytes, the size of a single + . +- `TransmittedWords` is set to 100 bytes. This simulates the amount of data + required to e.g. send a stimulus waveform. -For many experiments, the above latency is totally acceptable. In any case, let's see how much lower -we can get the latency for more intense closed-loop experiments. +> [!NOTE] +> The `DeviceAddress` must be manually configured because +> is used for diagnostics and testing +> and therefore is not made available through +> like the rest of the local +> devices (analog IO, digital IO, etc.) + +Next we configure 's + + properties. `WriteSize` is set +to 16384 bytes. This defines a readily-available pool of memory for the creation +of output data frames. A larger size will reduce the frequency of dynamic memory +allocation system calls but increase the expense of each of those calls. The +effect on real-time performance is typically not as large as that of the +`ReadSize` property because it does not determine when data is written to +hardware. Data is written to hardware as soon as an output frame has been +created. To start, we also set the `ReadSize` property is also set to 16384. In +the next section, we'll examine the effect of this value on real time +performance. + +### Real-time Loop +The bottom half of the workflow is used to stream data back to the load testing +device from hardware so that it can perform a measurement of round trip latency. +The operator acquires a sequence of +[LoadTesterDataFrames](xref:OpenEphys.Onix1.LoadTesterDataFrame) from the +hardware each of which is split into its + member and + member. + +::: workflow +![SVG of load tester workflow loadtester branch](../../workflows/tutorials/tune-readsize/loadtester.bonsai) +::: -#### ReadSize = 2048 +The `HubClock` member indicates the acquisition clock count when the +`LoadTesterDataFrame` was produced. The `EveryNth` operator is a + which only allows through every Nth element in +the observable sequence. This is used to simulate an algorithm, such as spike +detection, that only triggers closed loop feedback in response to input data +meeting some condition. The value of `N` can be changed to simulate different +feedback frequencies. You can inspect its logic by double-clicking the node when +the workflow is not running. In this case, `N` is set to 100, so every 100th +sample is sent to operator. + +`LoadTesterLoopback` a *sink* which writes the HubClock member that was passed +through the EveryNth operator back to the load tester device. When this value is +received in the hardware its subtracted from the current acquisition clock count +value and is sent with the `HubClockDelta` value of subsequent +`LoadTesterDataFrames`. Therefore, `HubClockDelta` indicates the amount of time +that has passed since the creation of it frame in hardware and the receipt of a +feedback signal in hardware based on that frame: it is a complete measurement of +closed loop latency. This value is converted to milliseconds and then + is used to to help visualize the distribution of +closed-loop latencies. + +Finally, at the bottom of the workflow, a + operator is used to examine the state +of the hardware buffer. To learn about the + branch, visit the [Breakout Board +Memory Monitor](xref:breakout_memory-monitor) (or the equivalent for any of our +other hardware) page. + +::: workflow +![SVG of load tester workflow memorymonitor branch](../../workflows/tutorials/tune-readsize/memory-monitor.bonsai) +::: -Set ReadSize to 2048 and restart the workflow (ReadSize is a +### Real-time Latency for Different ReadSize Values + +#### ReadSize = 16384 bytes +With `ReadSize` set to 16384 bytes, start the workflow, and +[open the visualizers](xref:visualize-data) for the PercentUsed and Histogram1D +nodes: + +![screenshot of Histogram1D visualizers with ReadSize 16384](../../images/tutorials/tune-readsize/histogram1d_16384.webp) +![screenshot of PercentUsed visualizers with ReadSize 16384](../../images/tutorials/tune-readsize/percent-used_16384.webp) + +Data is produced at about 47MB/s. Therefore it takes about 340 μs to accumulate +16384 bytes. This means that the _oldest data_ in the buffer is from 350 μs in +the past. Because we are using only every `N`th sample to generate feedback, the +sample that is actually used to trigger an output could be more recent than this +resulting in a latency lower then 350 us. Indeed, we see the average latency in +the histogram is ~300 μs (in this plot, 1000 corresponds to 1 ms). and can be as +low as ~60 μs. The long tail in the distribution corresponds to instances when +the hardware buffer was used or the operating system was busy with other tasks. + +With `ReadSize` of 16384 bytes, the PercentUsed Visualizer shows that the +percent of RAM in the Hardware Buffer being used remains close to zero. This +indicates that the Hardware Buffer is generally being bypassed because data is +being read more quickly by the host than it is produced by the hardware. For +many experiments, the above latency is more than acceptable. In any case, let's +see how much lower we can get the latency for more extreme closed-loop +experiments. + +#### ReadSize = 16384 bytes +Set `ReadSize` to 2048 bytes and restart the workflow (ReadSize is a [](xref:OpenEphys.Onix1#configuration) -property so it only updates when a workflow starts), and open the same visualizers: +property so it only updates when a workflow starts), and open the same visualizers: -![screenshot of Histogram1D visualizers with ReadSize 2048](../../images/tutorials/tune-readsize/histogram1d_2048.webp) -![screenshot of PercentUsed visualizers with ReadSize 2048](../../images/tutorials/tune-readsize/percent-used_2048.webp) +![screenshot of Histogram1D visualizers with ReadSize 2048](../../images/tutorials/tune-readsize/histogram1d_2048.webp) +![screenshot of PercentUsed visualizers with ReadSize 2048](../../images/tutorials/tune-readsize/percent-used_2048.webp) -The closed-loop latencies now average about 80 μs. The hardware buffer still seems pretty stable -around zero even after letting some time pass. Let's see if we can decrease latency even further -without overflowing the buffer. +The closed-loop latencies now average about 80 μs. The hardware buffer is still +stable at around around zero indicating that, even given the increased overhead +associated with a smaller `ReadSize`, software is collecting data rapdily enough +to prevent accumlation in the hardware buffer. Let's see if we can decrease +latency even further. #### ReadSize = 1024 -Set ReadSize to 1024, restart the workflow, and open the same visualizers. +Set `ReadSize` to 1024 bytes, restart the workflow, and open the same visualizers. -![screenshot of Histogram1D visualizers with ReadSize 1024](../../images/tutorials/tune-readsize/histogram1d_1024.webp) -![screenshot of PercentUsed visualizers with ReadSize 1024](../../images/tutorials/tune-readsize/percent-used_1024.webp) +![screenshot of Histogram1D visualizers with ReadSize 1024](../../images/tutorials/tune-readsize/histogram1d_1024.webp) +![screenshot of PercentUsed visualizers with ReadSize 1024](../../images/tutorials/tune-readsize/percent-used_1024.webp) -The Histogram1D visualizer appears to be empty. This is because the latency immediately exceeds the -upper limit x-axis of 1 ms. You can see this by inspecting the visualizer for the node prior to -Histogram1D. Because the computer cannot keep up with the amount of read operations necessary to -clear the buffer, there is a bunch of data in the queue that needs to be read before the most recent -data frames are accessible. Therefore, by the time a particular data frame gets read from the -buffer, a bunch of time has already passed since that frame was generated. This means it takes -longer for a given HubClock value to reach the LoadTesterLoopBack operator which subsequently means -increased latencies. +The Histogram1D visualizer appears to be empty. This is because the latency +immediately exceeds the upper limit x-axis of 1 ms. You can see this by +inspecting the visualizer for the node prior to Histogram1D. Because of the very +small buffer size, which corresponds to approximately a single Neuropixel 2.0 +sample, the computer cannot perform read operations at a rate required to keep +up with data production. Therefore data accumulates in the hardware buffer. By +the time a particular data frame gets read from the buffer, a bunch of time has +already passed since that frame was generated, latencies are increased +dramatically, and closed loop performance collapses. -Because the amount of data in the hardware buffer is rising (which can be seen by looking at the -MemoryMonitor PercentUsed visualizer), the acquisition session will eventually terminate in an error -when the MemoryMonitor PercentUsed reaches 100% and the hardware buffer overflows. - -> [!NOTE] -> The point at which your computer will not be able to keep up with with the number of reads to keep -> the buffer clear as demonstrated here depends on your computer's capabilities and might be -> different from when our computer can no longer do that. The computer used to create this tutorial -> has the following specs: -> - CPU: Intel i9-12900K -> - RAM: 64 GB -> - GPU: NVIDIA GTX 1070 8GB -> - OS: Windows 11 +Because the amount of data in the hardware buffer is rising (which can be seen +by looking at the MemoryMonitor PercentUsed visualizer), the acquisition session +will eventually terminate in an error when the MemoryMonitor PercentUsed reaches +100% and the hardware buffer overflows. #### Summary The results of our experimentation are as follows: -| ReadSize | Latency | Buffer Usage | Notes | -|----------|----------------------|-----------------|----------------------------------------------------------------------------------------------------| -| 16384 | ~300 μs | Stable at 0% | Perfectly fine if there aren't any strict low latency requirements, lowest risk of buffer overflow | -| 2048 | ~80 μs | Stable near 0% | Balances latency requirements with low risk of buffer overflow | -| 1024 | Rises steadily | Rises untenably | Certain buffer overflow error | - -These results may differ for your experimental system. For example, your system might have different -bandwidth requirements (if you are using different devices, data is produced at a different rate) or -use a computer with different performance capabilities (which changes how quickly it can perform -read operations). +| ReadSize | Latency | Buffer Usage | Notes | +|---------------|----------------------|-----------------|----------------------------------------------------------------------------------------------------| +| 16384 bytes | ~300 μs | Stable at 0% | Perfectly fine if there aren't any strict low latency requirements, lowest risk of buffer overflow | +| 2048 bytes | ~80 μs | Stable near 0% | Balances latency requirements with low risk of buffer overflow | +| 1024 bytes | Rises steadily | Unstable | Certain buffer overflow and terrible closed loop performance | + +These results may differ for your experimental system. For example, your system +might have different bandwidth requirements (if you are using different devices, +data is produced at a different rate) or use a computer with different +performance capabilities (which changes how quickly it can perform read +operations). Additionally, in this tutorial, there was minimal computational +load imposed by the workflow itself. In most applications, some interesting +processing must be performed on the data in order for a feedback signal to be +generated. Its important to take this into account when tuning your system and +potentially modify the workflow to perform computations on incoming data in +order to account for the effect of computational demand on closed loop +performance. \ No newline at end of file From 9132eaa5b22985563680ec854b980777dd742bcf Mon Sep 17 00:00:00 2001 From: cjsha Date: Mon, 8 Sep 2025 09:52:03 -0400 Subject: [PATCH 04/11] Address jonnew's feedback in addition to some clarifying edits --- articles/tutorials/tune-readsize.md | 274 ++++++++++-------- ...ester-configuration_properties-editor.webp | Bin 0 -> 17628 bytes ...nfiguration_properties-editor_2x-64ch.webp | Bin 0 -> 17536 bytes 3 files changed, 147 insertions(+), 127 deletions(-) create mode 100644 images/tutorials/tune-readsize/load-tester-configuration_properties-editor.webp create mode 100644 images/tutorials/tune-readsize/load-tester-configuration_properties-editor_2x-64ch.webp diff --git a/articles/tutorials/tune-readsize.md b/articles/tutorials/tune-readsize.md index 17294acf..7a5e5400 100644 --- a/articles/tutorials/tune-readsize.md +++ b/articles/tutorials/tune-readsize.md @@ -7,9 +7,9 @@ This tutorial shows how to optimize the 's property for your specific data acquisition setup to minimize delays between data collection and computer -processing. This tutorial provide a method to tune `ReadSize` within the context -of your particular data sources and computer specifications in order to achieve -the fastest possible response times for closed-loop experiments. In most +processing. This tutorial provides a method to tune `ReadSize` within the +context of your particular data sources and computer specifications in order to +achieve the fastest possible response times for closed-loop experiments. In most situations, sub-200 microsecond closed-loop response times can be achieved. > [!NOTE] @@ -27,54 +27,61 @@ The ONIX **Hardware Buffer** consists of 2GB of dedicated RAM that belongs to the acquisition hardware (it is _not_ RAM in the host computer). The hardware buffer temporarily stores data that has not yet been transferred to the host. When the host software is consuming data optimally, the hardware -buffer is bypassed entirely and data flows directly from production to the -host RAM, minimizing the latency between data collection and processing. +buffer is bypassed entirely and data flows directly from production to the host +computer's RAM, minimizing the latency between data collection and processing. Each time the host software reads data from the hardware, it obtains -**ReadSize** bytes of data using the following procedure: - -1. A block of memory that is `ReadSize` bytes long is allocated by the API -2. A pointer to that memory is provided to the kernel driver, which locks it - into kernel mode and initiates a [DMA - transfer](https://en.wikipedia.org/wiki/Direct_memory_access) from the - hardware. -3. The transfer is performed by the ONIX hardware without CPU intervention and - completes once `ReadSize` bytes have been produced. -4. Upon transfer completion, the buffer is passed back to user mode and the API - function returns with a pointer to the filled buffer. - -There are a couple of things to note about this process: +**ReadSize** bytes of data using the following procedure: + +1. A block of memory that is `ReadSize` bytes long is allocated on the host by + the API for the purpose of holding incoming data from ONIX hardware. +2. A pointer to that memory is provided to the + [RIFFA](https://open-ephys.github.io/ONI/v1.0/api/liboni/driver-translators/riffa.html) + driver (the PCIe backend of the ONIX system) which moves the allocated memory + block into a more privileged state known as kernel mode so that it can + initiate a + [DMA transfer](https://en.wikipedia.org/wiki/Direct_memory_access). DMA + allows data transfer to be performed by ONIX hardware without additional CPU + intervention. +3. The data transfer completes once `ReadSize` bytes have been produced. The + RIFFA driver moves the memory block from kernel mode to user mode so that it + can be accessed by software. The API function returns with a pointer to the + filled buffer. + +The key take-away points about this process are: 1. Memory is allocated only once by the API, and the transfer is [zero-copy](https://en.wikipedia.org/wiki/Zero-copy). ONIX hardware writes - directly into the API-allocated buffer autonomously without using the host - computer's resources. Within this process, `ReadSize` determines the amount + directly into the API-allocated buffer autonomously using minimal resources + from the host computer. Within this process, `ReadSize` determines the amount of data that is transferred each time the API reads data from the hardware. -2. If the buffer is allocated and the transfer initiated by the host API before - data is produced by the hardware, the data is transferred directly into the - buffer and completely bypasses the Hardware Buffer. In this case, hardware is - literally streaming data to the software buffer _the moment it is produced_. - It is physically impossible to achieve lower latencies than this situation. - The goal of this tutorial is to allow your system to operate in this regime. - -The size of hardware to host data transfers is determined by the +2. If the buffer is allocated and the transfer is initiated by the host API + before data is produced by the hardware, the data is transferred directly + into the software buffer and completely bypasses the Hardware Buffer. In this + case, hardware is literally streaming data to the software buffer _the moment + it is produced_. It is physically impossible to achieve lower latencies than + this situation. The goal of this tutorial is to allow your system to operate + in this regime. + +The size of hardware-to-host data transfers is determined by the property of the -StartAcquisition operator, which is necessary for every workflow that uses +StartAcquisition operator which is in every workflow that uses to acquire data from ONIX. Choosing an optimal `ReadSize` value balances the tradeoff between latency and overall bandwidth. Smaller -`ReadSize` values mean that less data needs to accumulate before the kernel -driver relinquishes control of the buffer to software. This, in effect, means -less time needs to pass before software can start operating on data, and thus -lower-latency feedback loops can be achieved. However, because each transfer -requires calls to the kernel driver, they incur significant overhead. If -`ReadSize` is so low that the average time it takes to perform a data transfer -is longer than the time it takes the hardware to produce data, data will -accumulate in the Hardware Buffer. This will destroy real-time performance and -eventually cause the hardware buffer to overflow, terminating acquisition. - -## Tuning ReadSize to Optimize Closed Loop Performance +`ReadSize` values mean that less data is required before the RIFFA driver +relinquishes control of the buffer to software. This, in effect, means software +can start operating on data closer to the time that the data was produced, and +thus lower-latency feedback loops can be achieved. However, each data transfer +requires calls to the RIFFA driver which incurs significant overhead. If +`ReadSize` is so low that it takes less time for the hardware to produce a +`ReadSize` amount of data than the average time it takes for the host computer +to read a `ReadSize` amount of data, the Hardware Buffer will excessively +accumulate data. This will destroy real-time performance and eventually cause +the hardware buffer to overflow, terminating acquisition. + +## Tuning `ReadSize` to Optimize Closed Loop Performance ONIX provides a mechanism for tuning the value of `ReadSize` to optimize closed -loop performance that takes into account the indosycncracies of your host +loop performance that takes into account the idiosyncrasies of your host computer and experimental acquisition setup. > [!NOTE] @@ -92,12 +99,10 @@ paste this workflow by clicking the Bonsai workflow editor pane and hitting ![SVG of load tester workflow](../../workflows/tutorials/tune-readsize/tune-readsize.bonsai) ::: - - ### Hardware Configuration The top-row configuration chain includes a operator. This configures ONIX's Load -Tester Device, which produces and consumes data at user specified rates for +Tester Device, which produces and consumes data at user-specified rates for testing and tuning the latency between data production and real-time feedback. This device is _not a emulator_. It is a real hardware device that produces and consumes data using the selected driver and physical link (e.g. PCIe bus) and @@ -124,10 +129,12 @@ $$ We'll setup `ConfigureLoadTester` to produce data at the same frequency and bandwidth as two Neuropixels 2.0 probes with the following settings: +screenshot of ConfigureLoadTester's property editor + - `DeviceAddress` is set to 11 because that's how this device is indexed in the ONIX system. -- `DeviceName` is set to "LoadTester" -- `Enable`is set to True to enable the LoadTester device. +- `DeviceName` is set to "Load Tester" +- `Enable` is set to True to enable the LoadTester device. - `FramesPerSecond` is then set to 60,000 Hz. The rate at which frames are produced by two probes. - `ReceivedWords` is set to 392 bytes, the size of a single @@ -151,8 +158,8 @@ allocation system calls but increase the expense of each of those calls. The effect on real-time performance is typically not as large as that of the `ReadSize` property because it does not determine when data is written to hardware. Data is written to hardware as soon as an output frame has been -created. To start, we also set the `ReadSize` property is also set to 16384. In -the next section, we'll examine the effect of this value on real time +created. To start, we also set the `ReadSize` property is also set to 16384. +Later in this tutorial, we'll examine the effect of this value on real-time performance. ### Real-time Loop @@ -170,119 +177,132 @@ hardware each of which is split into its The `HubClock` member indicates the acquisition clock count when the `LoadTesterDataFrame` was produced. The `EveryNth` operator is a - which only allows through every Nth element in -the observable sequence. This is used to simulate an algorithm, such as spike -detection, that only triggers closed loop feedback in response to input data -meeting some condition. The value of `N` can be changed to simulate different -feedback frequencies. You can inspect its logic by double-clicking the node when -the workflow is not running. In this case, `N` is set to 100, so every 100th -sample is sent to operator. - -`LoadTesterLoopback` a *sink* which writes the HubClock member that was passed -through the EveryNth operator back to the load tester device. When this value is -received in the hardware its subtracted from the current acquisition clock count -value and is sent with the `HubClockDelta` value of subsequent -`LoadTesterDataFrames`. Therefore, `HubClockDelta` indicates the amount of time -that has passed since the creation of it frame in hardware and the receipt of a -feedback signal in hardware based on that frame: it is a complete measurement of -closed loop latency. This value is converted to milliseconds and then - is used to to help visualize the distribution of -closed-loop latencies. + operator which only allows through every Nth +element in the observable sequence. This is used to simulate an algorithm, such +as spike detection, that only triggers closed loop feedback in response to input +data meeting some condition. The value of `N` can be changed to simulate +different feedback frequencies. You can inspect its logic by double-clicking the +node when the workflow is not running. In this case, `N` is set to 100, so every +100th sample is delivered to . + +`LoadTesterLoopback` is a *sink* which writes HubClock values it receives back +to the load tester device. When the load tester device receives a HubClock from +the host computer, it's subtracted from the current acquisition clock count. +That difference is sent back to the host computer as the `HubClockDelta` +property of subsequent `LoadTesterDataFrames`. In other words, `HubClockDelta` +indicates the amount of time that has passed since the creation of a frame in +hardware and the receipt of a feedback signal in hardware based on that frame: +it is a complete measurement of closed loop latency. This value is converted to +milliseconds and then is used to to help visualize +the distribution of closed-loop latencies. Finally, at the bottom of the workflow, a operator is used to examine the state of the hardware buffer. To learn about the branch, visit the [Breakout Board -Memory Monitor](xref:breakout_memory-monitor) (or the equivalent for any of our -other hardware) page. +Memory Monitor](xref:breakout_memory-monitor) page. ::: workflow ![SVG of load tester workflow memorymonitor branch](../../workflows/tutorials/tune-readsize/memory-monitor.bonsai) ::: -### Real-time Latency for Different ReadSize Values +### Real-time Latency for Different `ReadSize` Values -#### ReadSize = 16384 bytes +#### `ReadSize` = 16384 bytes With `ReadSize` set to 16384 bytes, start the workflow, and [open the visualizers](xref:visualize-data) for the PercentUsed and Histogram1D nodes: -![screenshot of Histogram1D visualizers with ReadSize 16384](../../images/tutorials/tune-readsize/histogram1d_16384.webp) -![screenshot of PercentUsed visualizers with ReadSize 16384](../../images/tutorials/tune-readsize/percent-used_16384.webp) - -Data is produced at about 47MB/s. Therefore it takes about 340 μs to accumulate -16384 bytes. This means that the _oldest data_ in the buffer is from 350 μs in -the past. Because we are using only every `N`th sample to generate feedback, the -sample that is actually used to trigger an output could be more recent than this -resulting in a latency lower then 350 us. Indeed, we see the average latency in -the histogram is ~300 μs (in this plot, 1000 corresponds to 1 ms). and can be as -low as ~60 μs. The long tail in the distribution corresponds to instances when -the hardware buffer was used or the operating system was busy with other tasks. - -With `ReadSize` of 16384 bytes, the PercentUsed Visualizer shows that the -percent of RAM in the Hardware Buffer being used remains close to zero. This -indicates that the Hardware Buffer is generally being bypassed because data is -being read more quickly by the host than it is produced by the hardware. For -many experiments, the above latency is more than acceptable. In any case, let's -see how much lower we can get the latency for more extreme closed-loop -experiments. - -#### ReadSize = 16384 bytes -Set `ReadSize` to 2048 bytes and restart the workflow (ReadSize is a +![screenshot of Histogram1D visualizers with `ReadSize` 16384](../../images/tutorials/tune-readsize/histogram1d_16384.webp) +![screenshot of PercentUsed visualizers with `ReadSize` 16384](../../images/tutorials/tune-readsize/percent-used_16384.webp) + +Since data is produced at about 47MB/s, it takes about 340 μs to produce 16384 +bytes of data. This means that the data contained in a single `ReadSize` block +was generated in the span of approximately 340 μs. Because we are using every +100th sample to generate feedback, the sample that is actually used to trigger +an output could be any from that 340 μs span resulting in latencies that are +lower then 340 μs. This is reflected in the Histogram1D visualizer. The average +latency is ~300 μs (in this plot, 1000 corresponds to 1 ms) and can be as low as +~60 μs. The long tail in the distribution corresponds to instances when the +hardware buffer was used or the operating system was busy with other tasks. + +With `ReadSize` of 16384 bytes, the PercentUsed visualizer shows that the +percent of the Hardware Buffer being used remains close to zero. This indicates +that the Hardware Buffer is generally being bypassed because data is being read +more quickly by the host than it is produced by the hardware. For experiments +without hard real-time constraints, this latency is perfectly acceptable. For +experiments with hard real-time constraints, let's see how low we can get the +closed-loop latency. + +#### `ReadSize` = 2048 bytes +Set `ReadSize` to 2048 bytes, restart the workflow (`ReadSize` is a [](xref:OpenEphys.Onix1#configuration) property so it only updates when a workflow starts), and open the same visualizers: -![screenshot of Histogram1D visualizers with ReadSize 2048](../../images/tutorials/tune-readsize/histogram1d_2048.webp) -![screenshot of PercentUsed visualizers with ReadSize 2048](../../images/tutorials/tune-readsize/percent-used_2048.webp) +![screenshot of Histogram1D visualizers with `ReadSize` 2048](../../images/tutorials/tune-readsize/histogram1d_2048.webp) +![screenshot of PercentUsed visualizers with `ReadSize` 2048](../../images/tutorials/tune-readsize/percent-used_2048.webp) The closed-loop latencies now average about 80 μs. The hardware buffer is still stable at around around zero indicating that, even given the increased overhead -associated with a smaller `ReadSize`, software is collecting data rapdily enough -to prevent accumlation in the hardware buffer. Let's see if we can decrease -latency even further. +associated with a smaller `ReadSize`, software is collecting data rapidly enough +to prevent excessive accumulation in the hardware buffer. Let's see if we can +decrease latency even further. -#### ReadSize = 1024 +#### `ReadSize` = 1024 bytes Set `ReadSize` to 1024 bytes, restart the workflow, and open the same visualizers. -![screenshot of Histogram1D visualizers with ReadSize 1024](../../images/tutorials/tune-readsize/histogram1d_1024.webp) -![screenshot of PercentUsed visualizers with ReadSize 1024](../../images/tutorials/tune-readsize/percent-used_1024.webp) +![screenshot of Histogram1D visualizers with `ReadSize` 1024](../../images/tutorials/tune-readsize/histogram1d_1024.webp) +![screenshot of PercentUsed visualizers with `ReadSize` 1024](../../images/tutorials/tune-readsize/percent-used_1024.webp) The Histogram1D visualizer appears to be empty. This is because the latency -immediately exceeds the upper limit x-axis of 1 ms. You can see this by +immediately exceeds the x-axis upper limit of 1 ms. You can see this by inspecting the visualizer for the node prior to Histogram1D. Because of the very -small buffer size, which corresponds to approximately a single Neuropixel 2.0 -sample, the computer cannot perform read operations at a rate required to keep -up with data production. Therefore data accumulates in the hardware buffer. By -the time a particular data frame gets read from the buffer, a bunch of time has -already passed since that frame was generated, latencies are increased -dramatically, and closed loop performance collapses. - -Because the amount of data in the hardware buffer is rising (which can be seen -by looking at the MemoryMonitor PercentUsed visualizer), the acquisition session -will eventually terminate in an error when the MemoryMonitor PercentUsed reaches -100% and the hardware buffer overflows. +small buffer size (which is on the order of a single Neuropixel 2.0 sample), the +computer cannot perform read operations at a rate required to keep up with data +production. This causes excessive accumulation of data in the hardware buffer. +The most recently produced data is added to the end of the hardware buffer's +queue, requiring several read operations before it can be read. As more data +accumulates in the buffer, the duration of time from when that data was produced +and when that data can finally be read increases. In other words, latencies +increase dramatically, and closed loop performance collapses. + +Because the amount of data in the hardware buffer is increasing (which is +indicated by the steadily rising PercentUsed visualizer), the acquisition +session will eventually terminate in an error when the MemoryMonitor PercentUsed +reaches 100% and the hardware buffer overflows. #### Summary The results of our experimentation are as follows: -| ReadSize | Latency | Buffer Usage | Notes | -|---------------|----------------------|-----------------|----------------------------------------------------------------------------------------------------| -| 16384 bytes | ~300 μs | Stable at 0% | Perfectly fine if there aren't any strict low latency requirements, lowest risk of buffer overflow | -| 2048 bytes | ~80 μs | Stable near 0% | Balances latency requirements with low risk of buffer overflow | -| 1024 bytes | Rises steadily | Unstable | Certain buffer overflow and terrible closed loop performance | +| `ReadSize` | Latency | Buffer Usage | Notes | +|-------------|----------------|----------------|----------------------------------------------------------------------------------------------------| +| 16384 bytes | ~300 μs | Stable at 0% | Perfectly adequate if there are no strict low latency requirements, lowest risk of buffer overflow | +| 2048 bytes | ~80 μs | Stable near 0% | Balances latency requirements with low risk of buffer overflow | +| 1024 bytes | Rises steadily | Unstable | Certain buffer overflow and terrible closed loop performance | These results may differ for your experimental system. For example, your system might have different bandwidth requirements (if you are using different devices, data is produced at a different rate) or use a computer with different -performance capabilities (which changes how quickly it can perform read -operations). Additionally, in this tutorial, there was minimal computational -load imposed by the workflow itself. In most applications, some interesting -processing must be performed on the data in order for a feedback signal to be -generated. Its important to take this into account when tuning your system and -potentially modify the workflow to perform computations on incoming data in -order to account for the effect of computational demand on closed loop -performance. - - \ No newline at end of file +performance capabilities (which changes how quickly read operations can occur). +For example, here is a similar table made by configuring the Load Tester +device to produce data at a rate similar to two 64-channel Intan chips (such +as what is on the ): + +![screenshot of ConfigureLoadTester's property editor for two Intan chips](../../images/tutorials/tune-readsize/load-tester-configuration_properties-editor_2x-64ch.webp) + +| `ReadSize` | Latency | Buffer Usage | Notes | +|------------|----------------|----------------|---------------------------------------------------------------------------------------------------| +| 1024 bytes | ~200 μs | Stable at 0% | Perfectly adequate if that are no strict low latency requirements, lowest risk of buffer overflow | +| 512 bytes | ~80 μs | Stable near 0% | Balances latency requirements with low risk of buffer overflow | +| 256 bytes | Rises steadily | Unstable | Certain buffer overflow and terrible closed loop performance | + +Additionally, in this tutorial, there was minimal computational load imposed by +the workflow itself. In most applications, some processing is performed on the +data to generate the feedback signal. Its important to take this into account +when tuning your system and potentially modifying the workflow to perform +computations on incoming data in order to account for the effect of +computational demand on closed loop performance. + + \ No newline at end of file diff --git a/images/tutorials/tune-readsize/load-tester-configuration_properties-editor.webp b/images/tutorials/tune-readsize/load-tester-configuration_properties-editor.webp new file mode 100644 index 0000000000000000000000000000000000000000..53997149824709a93358a3752d48f78837917ea9 GIT binary patch literal 17628 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 literal 0 HcmV?d00001 diff --git a/images/tutorials/tune-readsize/load-tester-configuration_properties-editor_2x-64ch.webp b/images/tutorials/tune-readsize/load-tester-configuration_properties-editor_2x-64ch.webp new file mode 100644 index 0000000000000000000000000000000000000000..c505f70010c30493b1a4cd16ef744937844c11b1 GIT binary patch literal 17536 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 i;6EPtj|cwaf&X~mKOXph&jbH#ZJb}{&0P!t literal 0 HcmV?d00001 From 0f404a5114833f282995f9ab88422617a02563ef Mon Sep 17 00:00:00 2001 From: cjsha Date: Wed, 10 Sep 2025 13:34:21 -0400 Subject: [PATCH 05/11] Change load tester configuration for 1 intan device not 2 - Populate the second table accordingly. - Change the properties screenshot. - Add additional explanation for the second table. --- articles/tutorials/tune-readsize.md | 46 ++++++++++++------ ...nfiguration_properties-editor_2x-64ch.webp | Bin 17536 -> 0 bytes ...-configuration_properties-editor_64ch.webp | Bin 0 -> 16830 bytes .../percent-used_256_lower-payload.png | Bin 0 -> 6749 bytes 4 files changed, 30 insertions(+), 16 deletions(-) delete mode 100644 images/tutorials/tune-readsize/load-tester-configuration_properties-editor_2x-64ch.webp create mode 100644 images/tutorials/tune-readsize/load-tester-configuration_properties-editor_64ch.webp create mode 100644 images/tutorials/tune-readsize/percent-used_256_lower-payload.png diff --git a/articles/tutorials/tune-readsize.md b/articles/tutorials/tune-readsize.md index 7a5e5400..95a33354 100644 --- a/articles/tutorials/tune-readsize.md +++ b/articles/tutorials/tune-readsize.md @@ -285,24 +285,38 @@ The results of our experimentation are as follows: These results may differ for your experimental system. For example, your system might have different bandwidth requirements (if you are using different devices, data is produced at a different rate) or use a computer with different -performance capabilities (which changes how quickly read operations can occur). -For example, here is a similar table made by configuring the Load Tester -device to produce data at a rate similar to two 64-channel Intan chips (such -as what is on the ): - -![screenshot of ConfigureLoadTester's property editor for two Intan chips](../../images/tutorials/tune-readsize/load-tester-configuration_properties-editor_2x-64ch.webp) - -| `ReadSize` | Latency | Buffer Usage | Notes | -|------------|----------------|----------------|---------------------------------------------------------------------------------------------------| -| 1024 bytes | ~200 μs | Stable at 0% | Perfectly adequate if that are no strict low latency requirements, lowest risk of buffer overflow | -| 512 bytes | ~80 μs | Stable near 0% | Balances latency requirements with low risk of buffer overflow | -| 256 bytes | Rises steadily | Unstable | Certain buffer overflow and terrible closed loop performance | - -Additionally, in this tutorial, there was minimal computational load imposed by +performance capabilities (which changes how quickly read operations can occur). +For example, here is a similar table made by configuring the Load Tester device +to produce data at a rate similar to a single 64-channel Intan chip (such as +what is on the ), ~4.3 MB/s: + +![screenshot of ConfigureLoadTester's property editor for a single Intan chips](../../images/tutorials/tune-readsize/load-tester-configuration_properties-editor_64ch.webp) + +| `ReadSize` | Latency | Buffer Usage | Notes | +|------------|----------------|--------------|-----------------------------------------------------------------------------------| +| 1024 bytes | ~200 μs | Stable at 0% | Perfectly adequate if that are no strict low latency requirements | +| 512 bytes | ~110 μs | Stable at 0% | Lower latency, no risk of buffer overflow | +| 256 bytes | ~80 μs | Stable at 0% | Lowest achievable latency with this setup, still no risk of buffer overflow | +| 128 bytes | - | - | Results in error -- 128 bytes is too small for the current hardware configuration | + +Regarding the last row of the above table, the lowest `ReadSize` possible is +determined by the size of the largest data frame produced by enabled devices +(plus some overhead). Even with the lowest possible `ReadSize` value, 256 bytes, +there is very little risk of overflowing the buffer. The PercentUsed visualizer +shows that the hardware buffer does not accumulate data: + +![](../../images/tutorials/tune-readsize/percent-used_256_lower-payload.png) + +These two tables together demonstrates why it is impossible to recommend a +single correct value for `ReadSize` that is adequate for all experiments. The +diversity of experiments (in particular, the wide range at which they produce +data) requires a range of `ReadSize` values. + +Last, in this tutorial, there was minimal computational load imposed by the workflow itself. In most applications, some processing is performed on the -data to generate the feedback signal. Its important to take this into account +data to generate the feedback signal. It's important to take this into account when tuning your system and potentially modifying the workflow to perform computations on incoming data in order to account for the effect of computational demand on closed loop performance. - \ No newline at end of file + \ No newline at end of file diff --git a/images/tutorials/tune-readsize/load-tester-configuration_properties-editor_2x-64ch.webp b/images/tutorials/tune-readsize/load-tester-configuration_properties-editor_2x-64ch.webp deleted file mode 100644 index c505f70010c30493b1a4cd16ef744937844c11b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17536 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 i;6EPtj|cwaf&X~mKOXph&jbH#ZJb}{&0P!t diff --git a/images/tutorials/tune-readsize/load-tester-configuration_properties-editor_64ch.webp b/images/tutorials/tune-readsize/load-tester-configuration_properties-editor_64ch.webp new file mode 100644 index 0000000000000000000000000000000000000000..c1269a0d5ea812cd34d561c4cef1bc08896f6945 GIT binary patch literal 16830 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

W}xYfP4et?2~@a5?cfKu4x#PZXv4xTyC@W-J2 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 E1zUO`8UO$Q literal 0 HcmV?d00001 diff --git a/images/tutorials/tune-readsize/percent-used_256_lower-payload.png b/images/tutorials/tune-readsize/percent-used_256_lower-payload.png new file mode 100644 index 0000000000000000000000000000000000000000..80c50807ebe33848b00e4626e5ea9f56d7c1b71f GIT binary patch literal 6749 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 MQPEb0-?Iw)FMOui^Z)<= literal 0 HcmV?d00001 From e7f8eb9377c9877f398a73f9c911c5857726a760 Mon Sep 17 00:00:00 2001 From: cjsha <36574350+cjsha@users.noreply.github.com> Date: Tue, 16 Sep 2025 17:36:06 -0400 Subject: [PATCH 06/11] Issue 255 25 ch (#270) chuckles feedback for read-size tutorial + edits --------- Co-authored-by: Ceci Herbert Co-authored-by: Ceci Herbert --- api/data-elements.md | 93 ++++++- articles/tutorials/tune-readsize.md | 383 +++++++++++++++++----------- 2 files changed, 322 insertions(+), 154 deletions(-) diff --git a/api/data-elements.md b/api/data-elements.md index aa643347..110fd5bc 100644 --- a/api/data-elements.md +++ b/api/data-elements.md @@ -3,4 +3,95 @@ uid: data-elements title: Data Elements --- -Data elements are produced by Bonsai operators. \ No newline at end of file +Data elements are produced by Bonsai operators. These +pages contain information data elements that can help interpret and load data +produced by . + +In general, a data element comprises of properties which together contain +timestamped data from a particular device. For example, + outputs +[Bno055DataFrames](xref:OpenEphys.Onix1.Bno055DataFrame) which contains data +produced by a BNO055 device: +- The data produced by the BNO055 is contained in the Acceleration, + Calibration, EulerAngle, Gravity, and Temperature properties of the + Bno055DataFrame. Any of these properties can be individually selected and + [visualized](xref:visualize-data) in Bonsai. +- The property contains the precise + hardware timestamp for the data in the properties described in the first + bullet point created using the global ONIX Controller clock. This Clock + property can be used to sync BNO055 data with data from all other devices + from which ONIX is acquiring and put it all onto the same timeline. +- The property contains the precise + hardware timestamp created using the clock on the hardware that contains + the device. + +There are some exceptions to the pattern described above. For example: +- is an object passed through the + configuration chain for writing to and reading from the ONIX hardware. +- outputs the parameters used to + set the precise hardware output clock when the workflow starts. + +These pages also describe the type of each property. This type information can +be used to calculate the rate of data produced by the devices enabled in your +experiment. For example, the operator +(which outputs the data from a single Neuropixels 2.0 probe device) produces a +sequence of +[NeuropixelsV2eDataFrames](xref:OpenEphys.Onix1.NeuropixelsV2eDataFrame). Using +the fact that each sample comprises of a Clock property (8 bytes), a HubClock +property (8 bytes), and an AmplifierData property (384*2 bytes), this device's +data rate is: + +$$ +\begin{equation} + \frac{2*384+8+8\,bytes}{sample}*\frac{30,000\,samples}{s}*\frac{1\,MB}{10^6bytes} = 23.52\,MB/s + \label{eq:1x_npx2_bw} +\end{equation} +$$ + +NeuropixelsV2eDataFrame is actually a buffered data frame (as indicated by the +presence of NeuropixelsV2eData's BufferSize property), meaning that several data +samples and their timestamps are buffered into a single NeuropixelsV2eDataFrame. +The above calculation was calculated under the assumption that +NeuropixelsV2eData's BufferSize property is set to 1. Although the calculation +is slightly different when BufferSize is more than 1, the end result ends up +being the same. When BufferSize is more than 1, NeuropixelsV2eDataFrames are +produced at a rate 30 kHz divided by the value of BufferSize. Each +NeuropixelsV2eDataFrame comprises of: + +- a Clock property: an array of ulong (each 8 bytes) of length N +- a HubClock property: an array of ulong (each 8 bytes) of length N +- an AmplifierData property: a of ushort (each 2 bytes) + of size 384 x N + +where N is a stand-in for BufferSize. Therefore, the calculation becomes: + +$$ +\begin{equation} + \frac{(2*384+8+8)*N\,bytes}{sample}*\frac{30,000/N\,samples}{s}*\frac{1\,MB}{10^6bytes} = 23.52\,MB/s + \label{eq:1x_npx2_bw_buffersize} +\end{equation} +$$ + +N cancels out and the result is the same. + +Knowing the type of each property can also be helpful in two more ways: + +- A property's type indicates how a property can be used in Bonsai. Operators + typically accept only a specific type or set of types as inputs. When types + don't match, Bonsai indicates an error. +- If a property is saved using a (i.e. as a raw + binary file), knowing its type informs how to load the data. For example, + the [dtypes](https://numpy.org/doc/stable/reference/arrays.dtypes.html) in + our [example Breakout Board data-loading script](xref:breakout_load-data) + were selected according to the size of each data being saved. For example, + digital input clock samples are saved using 8 bytes which requires + `dt=np.uint64` when loading, and digital input pin samples are saved using a + single byte which requires `dt=np.uint8` when loading. + + diff --git a/articles/tutorials/tune-readsize.md b/articles/tutorials/tune-readsize.md index 95a33354..086f6c75 100644 --- a/articles/tutorials/tune-readsize.md +++ b/articles/tutorials/tune-readsize.md @@ -3,83 +3,115 @@ uid: tune-readsize title: Optimizing Closed Loop Performance --- -This tutorial shows how to optimize the -'s - property for your specific data -acquisition setup to minimize delays between data collection and computer -processing. This tutorial provides a method to tune `ReadSize` within the -context of your particular data sources and computer specifications in order to -achieve the fastest possible response times for closed-loop experiments. In most -situations, sub-200 microsecond closed-loop response times can be achieved. +This tutorial shows how to retrieve data from the ONIX hardware as quickly as +possible for experiments with strict low-latency closed-loop requirements by +tuning the workflow for your particular data sources and computer +specifications. In most situations, sub-200 microsecond closed-loop response +times can be achieved. > [!NOTE] > Performance will vary based on your computer's capabilities and your results -> might differ those presented below. The computer used to create this tutorial +> might differ from those presented below. The computer used to create this tutorial > has the following specs: +> > - CPU: Intel i9-12900K > - RAM: 64 GB > - GPU: NVIDIA GTX 1070 8GB > - OS: Windows 11 -## Hardware Buffer and ReadSize - -The ONIX **Hardware Buffer** consists of 2GB of dedicated RAM -that belongs to the acquisition hardware (it is _not_ RAM in the host computer). -The hardware buffer temporarily stores data that has not yet been transferred to -the host. When the host software is consuming data optimally, the hardware -buffer is bypassed entirely and data flows directly from production to the host -computer's RAM, minimizing the latency between data collection and processing. - -Each time the host software reads data from the hardware, it obtains -**ReadSize** bytes of data using the following procedure: - -1. A block of memory that is `ReadSize` bytes long is allocated on the host by - the API for the purpose of holding incoming data from ONIX hardware. -2. A pointer to that memory is provided to the - [RIFFA](https://open-ephys.github.io/ONI/v1.0/api/liboni/driver-translators/riffa.html) - driver (the PCIe backend of the ONIX system) which moves the allocated memory - block into a more privileged state known as kernel mode so that it can - initiate a - [DMA transfer](https://en.wikipedia.org/wiki/Direct_memory_access). DMA - allows data transfer to be performed by ONIX hardware without additional CPU - intervention. -3. The data transfer completes once `ReadSize` bytes have been produced. The - RIFFA driver moves the memory block from kernel mode to user mode so that it - can be accessed by software. The API function returns with a pointer to the - filled buffer. - -The key take-away points about this process are: - -1. Memory is allocated only once by the API, and the transfer is - [zero-copy](https://en.wikipedia.org/wiki/Zero-copy). ONIX hardware writes - directly into the API-allocated buffer autonomously using minimal resources - from the host computer. Within this process, `ReadSize` determines the amount - of data that is transferred each time the API reads data from the hardware. -2. If the buffer is allocated and the transfer is initiated by the host API - before data is produced by the hardware, the data is transferred directly - into the software buffer and completely bypasses the Hardware Buffer. In this - case, hardware is literally streaming data to the software buffer _the moment - it is produced_. It is physically impossible to achieve lower latencies than - this situation. The goal of this tutorial is to allow your system to operate - in this regime. - -The size of hardware-to-host data transfers is determined by the - property of the -StartAcquisition operator which is in every workflow that uses - to acquire data from ONIX. Choosing an optimal `ReadSize` -value balances the tradeoff between latency and overall bandwidth. Smaller -`ReadSize` values mean that less data is required before the RIFFA driver -relinquishes control of the buffer to software. This, in effect, means software -can start operating on data closer to the time that the data was produced, and -thus lower-latency feedback loops can be achieved. However, each data transfer -requires calls to the RIFFA driver which incurs significant overhead. If -`ReadSize` is so low that it takes less time for the hardware to produce a -`ReadSize` amount of data than the average time it takes for the host computer -to read a `ReadSize` amount of data, the Hardware Buffer will excessively -accumulate data. This will destroy real-time performance and eventually cause -the hardware buffer to overflow, terminating acquisition. +## Data Transmission from ONIX Hardware to Host Computer + +ONIX is capable of transferring data directly from production to the +host computer. However, if the host is busy when ONIX starts +producing data, ONIX will temporarily store this new data in its hardware buffer +while it waits for the host to be ready to accept new data. + +Key details about this process: + +- The size of hardware-to-host data transfers is determined by the + property of the + operator which is in every Bonsai + workflow that uses to acquire data from ONIX. +- Increasing `ReadSize` allows the host to read larger chunks of data from + ONIX per read operation without significantly increasing the duration of the + read operation, therefore increasing the maximum rate at which data can be + read. +- If the host is busy or cannot perform read operations rapidly enough to keep + up with the rate at which ONIX produces data, the ONIX hardware buffer will + start to accumulate excessive data. +- Accumulation of excess data in the hardware buffer collapses real-time + performance and risks hardware buffer overflow which would prematurely + terminate the acquisition session. `ReadSize` can be increased to avoid this + situation. +- As long as this situation is avoided, decreasing `ReadSize` means that ONIX + doesn't needs to produce as much data before the host can access it. This, + in effect, means software can start operating on data closer to the time + that the data was produced, thus achieving lower-latency feedback-loops. + +In other words, a small `ReadSize` can help the host access data sooner to when +that data was created. However, each data transfer incurs overhead. If +`ReadSize` is so small that ONIX produces a `ReadSize` amount of data faster +than the average time it takes the host computer to perform a read operation, +the hardware buffer will accumulate excessive data. This will destroy real-time +performance and eventually cause the hardware buffer to overflow, terminating +acquisition. The goal of this tutorial is to tune StartAcquisition's `ReadSize` +so that data flows from production to the software running on the host as +quickly as possible by minimizing the amount of time that it sits idly in both +the ONIX hardware buffer and the API-allocated buffer. This provides software +access to the data as close to when the data was produced as possible which +helps achieve lower latencies closed-loop feedback. + +### Technical Details + +> [!NOTE] +> This section explains more in-depth how data is transferred from ONIX to the +> host computer. Although these details provide additional context about ONIX, +> they are more technical and are not required for following the rest of the +> tutorial. + +When the host computer reads data from the ONIX +hardware, it retrieves a **ReadSize**-bytes sized chunk of data using the +following procedure: + +1. A `ReadSize`-bytes long block of memory is allocated on the host computer's + RAM by the host API for the purpose of holding incoming data from ONIX. +1. A pointer to that memory is provided to the + [RIFFA](https://open-ephys.github.io/ONI/v1.0/api/liboni/driver-translators/riffa.html) + driver (the PCIe backend/kernel driver for the ONIX system) which moves the + allocated memory block into a more privileged state known as kernel mode so + that it can initiate a [DMA + transfer](https://en.wikipedia.org/wiki/Direct_memory_access). DMA allows + data transfer to be performed by ONIX hardware without additional CPU + intervention. +1. The data transfer completes once this block of data has been populated with + `ReadSize` bytes of data from ONIX. +1. The RIFFA driver moves the memory block from kernel mode to user mode so + that it can be accessed by software. The API function returns with a pointer + to the filled buffer. + +During this process, memory is allocated only once by the API, and the transfer +is [zero-copy](https://en.wikipedia.org/wiki/Zero-copy). The API-allocated +buffer is written autonomously by ONIX hardware using minimal resources from +the host computer. + +So far, all this occurs on the host-side. Meanwhile, on the ONIX-side: + +- If ONIX produces new data before the host is able to consume the data in the + API-allocated buffer, this new data is added to the back of ONIX hardware + buffer FIFO. The ONIX hardware buffer consists of 2GB of RAM that belongs to + the acquisition hardware (it is _not_ RAM in the host computer) dedicated to + temporarily storing data that is waiting to be transferred to the host. Data + is removed from front of the hardware buffer and transferred to the host + once it's ready to accept more data. +- If the memory is allocated on the host-side and the data transfer is + initiated by the host API before any data is produced, ONIX transfers new + data directly to the host bypassing the hardware buffer. In this case, ONIX + is literally streaming data to the host _the moment it is produced_. This + data becomes available for reading by the host once ONIX transfers the full + `ReadSize` bytes. ## Tuning `ReadSize` to Optimize Closed Loop Performance + ONIX provides a mechanism for tuning the value of `ReadSize` to optimize closed loop performance that takes into account the idiosyncrasies of your host computer and experimental acquisition setup. @@ -90,9 +122,9 @@ computer and experimental acquisition setup. > Bonsai environment and familiarize yourself with using the library to acquire > data from ONIX before proceeding. -Copy the following workflow into the Bonsai workflow editor by hovering over +Copy the following workflow into the Bonsai workflow editor by hovering over the workflow image and clicking on the clipboard icon that appears. Open Bonsai and -paste this workflow by clicking the Bonsai workflow editor pane and hitting +paste this workflow by clicking the Bonsai workflow editor pane and pressing Ctrl+V. ::: workflow @@ -100,11 +132,12 @@ paste this workflow by clicking the Bonsai workflow editor pane and hitting ::: ### Hardware Configuration + The top-row configuration chain includes a operator. This configures ONIX's Load Tester Device, which produces and consumes data at user-specified rates for testing and tuning the latency between data production and real-time feedback. -This device is _not a emulator_. It is a real hardware device that produces and +This device is _not an emulator_. It is a real hardware device that produces and consumes data using the selected driver and physical link (e.g. PCIe bus) and thus provides accurate measurements of feedback performance for a given host computer. @@ -126,43 +159,47 @@ $$ \end{equation} $$ +To understand how we came up with this calculation, visit the + page. + We'll setup `ConfigureLoadTester` to produce data at the same frequency and bandwidth as two Neuropixels 2.0 probes with the following settings: screenshot of ConfigureLoadTester's property editor -- `DeviceAddress` is set to 11 because that's how this device is indexed in the - ONIX system. -- `DeviceName` is set to "Load Tester" -- `Enable` is set to True to enable the LoadTester device. -- `FramesPerSecond` is then set to 60,000 Hz. The rate at which frames are - produced by two probes. -- `ReceivedWords` is set to 392 bytes, the size of a single - . -- `TransmittedWords` is set to 100 bytes. This simulates the amount of data - required to e.g. send a stimulus waveform. +- `DeviceAddress` is set to 11 because that's how this device is indexed in + the ONIX system. +- `DeviceName` is set to "Load Tester" +- `Enable` is set to True to enable the LoadTester device. +- `FramesPerSecond` is then set to 60,000 Hz. The rate at which frames are + produced by two probes, since each is acquired independently. +- `ReceivedWords` is set to 392 bytes, the size of a single + including its clock members. +- `TransmittedWords` is set to 100 bytes. This simulates the amount of data + required to e.g. send a stimulus waveform. > [!NOTE] > The `DeviceAddress` must be manually configured because > is used for diagnostics and testing > and therefore is not made available through > like the rest of the local -> devices (analog IO, digital IO, etc.) +> devices (analog IO, digital IO, etc.). The device address can be found using +> [oni-repl](https://open-ephys.github.io/onix-docs/Software%20Guide/oni-repl/usage.html#repl-commands). Next we configure 's - - properties. `WriteSize` is set -to 16384 bytes. This defines a readily-available pool of memory for the creation -of output data frames. A larger size will reduce the frequency of dynamic memory -allocation system calls but increase the expense of each of those calls. The -effect on real-time performance is typically not as large as that of the -`ReadSize` property because it does not determine when data is written to -hardware. Data is written to hardware as soon as an output frame has been -created. To start, we also set the `ReadSize` property is also set to 16384. -Later in this tutorial, we'll examine the effect of this value on real-time -performance. + and + properties. + +`WriteSize` is set to 16384 bytes. This defines a readily-available pool of +memory for the creation of output data frames. Data is written to hardware as +soon as an output frame has been created, so the effect on real-time performance +is typically not as large as that of the `ReadSize` property. + +To start,`ReadSize` is also set to 16384. Later in this tutorial, we'll examine +the effect of this value on real-time performance. ### Real-time Loop + The bottom half of the workflow is used to stream data back to the load testing device from hardware so that it can perform a measurement of round trip latency. The operator acquires a sequence of @@ -177,23 +214,23 @@ hardware each of which is split into its The `HubClock` member indicates the acquisition clock count when the `LoadTesterDataFrame` was produced. The `EveryNth` operator is a - operator which only allows through every Nth -element in the observable sequence. This is used to simulate an algorithm, such + operator which only allows through every Nth +element in the observable sequence. This is used to simulate an algorithm, such as spike detection, that only triggers closed loop feedback in response to input -data meeting some condition. The value of `N` can be changed to simulate +data meeting some condition. The value of `N` can be changed to simulate different feedback frequencies. You can inspect its logic by double-clicking the node when the workflow is not running. In this case, `N` is set to 100, so every 100th sample is delivered to . -`LoadTesterLoopback` is a *sink* which writes HubClock values it receives back -to the load tester device. When the load tester device receives a HubClock from -the host computer, it's subtracted from the current acquisition clock count. -That difference is sent back to the host computer as the `HubClockDelta` -property of subsequent `LoadTesterDataFrames`. In other words, `HubClockDelta` -indicates the amount of time that has passed since the creation of a frame in -hardware and the receipt of a feedback signal in hardware based on that frame: -it is a complete measurement of closed loop latency. This value is converted to -milliseconds and then is used to to help visualize +`LoadTesterLoopback` is a _sink_ which writes HubClock values it receives back +to the load tester device. When the load tester device receives a HubClock from +the host computer, it's subtracted from the current acquisition clock count. +That difference is sent back to the host computer as the `HubClockDelta` +property of subsequent `LoadTesterDataFrames`. In other words, `HubClockDelta` +indicates the amount of time that has passed since the creation of a frame in +hardware and the receipt of a feedback signal in hardware based on that frame: +it is a complete measurement of closed loop latency. This value is converted to +milliseconds and then is used to help visualize the distribution of closed-loop latencies. Finally, at the bottom of the workflow, a @@ -206,35 +243,60 @@ Memory Monitor](xref:breakout_memory-monitor) page. ![SVG of load tester workflow memorymonitor branch](../../workflows/tutorials/tune-readsize/memory-monitor.bonsai) ::: +### Relevant Visualizers + +The desired output of this workflow are the [visualizers](xref:visualize-data) +for the Histogram1D and PercentUsed nodes. Below is an example of each which we +will explore more in the next section: + +![screenshot of Histogram1D visualizers with `ReadSize` 16384](../../images/tutorials/tune-readsize/histogram1d_16384.webp) +![screenshot of PercentUsed visualizers with `ReadSize` 16384](../../images/tutorials/tune-readsize/percent-used_16384.webp) + +The Histogram1D visualizer shows the distribution of closed-loop feedback +latencies. The x-axis is in units of μs, and the y-axis represents the number of +samples in a particular bin. The histogram is configured to have 1000 bins +between 0 and 1000 μs. For low-latency closed-loop experiments, the goal is to +concentrate the distribution of closed-loop feedback latencies towards 0 μs as +much as possible. + +The PercentUsed visualizer shows a time-series of the amount of the hardware +buffer that is occupied by data as a percentage of the hardware buffer's total +capacity. The x-axis is timestamps, and the y-axis is percentage. To ensure data +is available as soon as possible from when it was produced and avoid potential +buffer overflow, the goal is to maintain the percentage at or near zero. + ### Real-time Latency for Different `ReadSize` Values #### `ReadSize` = 16384 bytes -With `ReadSize` set to 16384 bytes, start the workflow, and -[open the visualizers](xref:visualize-data) for the PercentUsed and Histogram1D -nodes: + +With `ReadSize` set to 16384 bytes, start the workflow and open the visualizers for the PercentUsed and +Histogram1D nodes: ![screenshot of Histogram1D visualizers with `ReadSize` 16384](../../images/tutorials/tune-readsize/histogram1d_16384.webp) ![screenshot of PercentUsed visualizers with `ReadSize` 16384](../../images/tutorials/tune-readsize/percent-used_16384.webp) -Since data is produced at about 47MB/s, it takes about 340 μs to produce 16384 -bytes of data. This means that the data contained in a single `ReadSize` block -was generated in the span of approximately 340 μs. Because we are using every -100th sample to generate feedback, the sample that is actually used to trigger -an output could be any from that 340 μs span resulting in latencies that are -lower then 340 μs. This is reflected in the Histogram1D visualizer. The average -latency is ~300 μs (in this plot, 1000 corresponds to 1 ms) and can be as low as -~60 μs. The long tail in the distribution corresponds to instances when the -hardware buffer was used or the operating system was busy with other tasks. - -With `ReadSize` of 16384 bytes, the PercentUsed visualizer shows that the -percent of the Hardware Buffer being used remains close to zero. This indicates -that the Hardware Buffer is generally being bypassed because data is being read -more quickly by the host than it is produced by the hardware. For experiments -without hard real-time constraints, this latency is perfectly acceptable. For -experiments with hard real-time constraints, let's see how low we can get the -closed-loop latency. +The Histogram1D visualizer shows that the average latency is about 300 μs, with +most latencies ranging from ~60 μs to ~400 μs. This roughly matches our +expectations. Since data is produced at about 47MB/s, it takes about 340 μs to +produce 16384 bytes of data. This means that the data contained in a single +`ReadSize` block was generated in the span of approximately 340 μs. Because we +are using every 100th sample to generate feedback, the sample that is actually +used to trigger LoadTesterLoopback could be any from that 340 μs span resulting +in a range of latencies. The long tail in the distribution corresponds to +instances when the hardware buffer was used or the CPU was busy with other +tasks. + +The PercentUsed visualizer shows that the percent of the hardware buffer being +used remains close to zero. This indicates minimal usage of the hardware buffer, +and that the host is safely reading data faster than the ONIX produces that +data. For experiments without hard real-time constraints, this latency is +perfectly acceptable. + +For experiments with harder real-time constraints, let's see how much lower we +can get the closed-loop latency. #### `ReadSize` = 2048 bytes + Set `ReadSize` to 2048 bytes, restart the workflow (`ReadSize` is a [](xref:OpenEphys.Onix1#configuration) property so it only updates when a workflow starts), and open the same visualizers: @@ -242,11 +304,14 @@ property so it only updates when a workflow starts), and open the same visualize ![screenshot of Histogram1D visualizers with `ReadSize` 2048](../../images/tutorials/tune-readsize/histogram1d_2048.webp) ![screenshot of PercentUsed visualizers with `ReadSize` 2048](../../images/tutorials/tune-readsize/percent-used_2048.webp) -The closed-loop latencies now average about 80 μs. The hardware buffer is still -stable at around around zero indicating that, even given the increased overhead -associated with a smaller `ReadSize`, software is collecting data rapidly enough -to prevent excessive accumulation in the hardware buffer. Let's see if we can -decrease latency even further. +The Histogram1D visualizer shows closed-loop latencies now average about 80 +μs with lower variability. + +The PercentUsed visualizer shows the hardware buffer is still stable at +around zero. This means that, even with the increased overhead associated +with a smaller `ReadSize`, the host is reading data rapidly enough to prevent +excessive accumulation in the hardware buffer. Let's see if we can decrease +latency even further. #### `ReadSize` = 1024 bytes @@ -258,26 +323,27 @@ Set `ReadSize` to 1024 bytes, restart the workflow, and open the same visualizer The Histogram1D visualizer appears to be empty. This is because the latency immediately exceeds the x-axis upper limit of 1 ms. You can see this by inspecting the visualizer for the node prior to Histogram1D. Because of the very -small buffer size (which is on the order of a single Neuropixel 2.0 sample), the -computer cannot perform read operations at a rate required to keep up with data -production. This causes excessive accumulation of data in the hardware buffer. -The most recently produced data is added to the end of the hardware buffer's -queue, requiring several read operations before it can be read. As more data -accumulates in the buffer, the duration of time from when that data was produced -and when that data can finally be read increases. In other words, latencies -increase dramatically, and closed loop performance collapses. - -Because the amount of data in the hardware buffer is increasing (which is -indicated by the steadily rising PercentUsed visualizer), the acquisition -session will eventually terminate in an error when the MemoryMonitor PercentUsed -reaches 100% and the hardware buffer overflows. +small buffer size (which is on the order of a single Neuropixels 2.0 sample), +the computer cannot perform read operations at a rate required to keep up with +data production. This causes excessive accumulation of data in the hardware +buffer. In this case, when new data is produced, it gets added to the end of the +hardware buffer queue, requiring several read operations before this new data +can be read. As more data accumulates in the buffer, the duration of time from +when that data was produced and when that data can finally be read increases. In +other words, latencies increase dramatically, and closed loop performance +collapses. + +The PercentUsed visualizer shows that the percentage of the hardware buffer that +is occupied is steadily increasing. The acquisition session will eventually +terminate in an error when the MemoryMonitor PercentUsed reaches 100% and the +hardware buffer overflows. #### Summary The results of our experimentation are as follows: | `ReadSize` | Latency | Buffer Usage | Notes | -|-------------|----------------|----------------|----------------------------------------------------------------------------------------------------| +| ----------- | -------------- | -------------- | -------------------------------------------------------------------------------------------------- | | 16384 bytes | ~300 μs | Stable at 0% | Perfectly adequate if there are no strict low latency requirements, lowest risk of buffer overflow | | 2048 bytes | ~80 μs | Stable near 0% | Balances latency requirements with low risk of buffer overflow | | 1024 bytes | Rises steadily | Unstable | Certain buffer overflow and terrible closed loop performance | @@ -292,12 +358,12 @@ what is on the ), ~4.3 MB/s: ![screenshot of ConfigureLoadTester's property editor for a single Intan chips](../../images/tutorials/tune-readsize/load-tester-configuration_properties-editor_64ch.webp) -| `ReadSize` | Latency | Buffer Usage | Notes | -|------------|----------------|--------------|-----------------------------------------------------------------------------------| -| 1024 bytes | ~200 μs | Stable at 0% | Perfectly adequate if that are no strict low latency requirements | -| 512 bytes | ~110 μs | Stable at 0% | Lower latency, no risk of buffer overflow | -| 256 bytes | ~80 μs | Stable at 0% | Lowest achievable latency with this setup, still no risk of buffer overflow | -| 128 bytes | - | - | Results in error -- 128 bytes is too small for the current hardware configuration | +| `ReadSize` | Latency | Buffer Usage | Notes | +| ---------- | ------- | ------------ | --------------------------------------------------------------------------------- | +| 1024 bytes | ~200 μs | Stable at 0% | Perfectly adequate if that are no strict low latency requirements | +| 512 bytes | ~110 μs | Stable at 0% | Lower latency, no risk of buffer overflow | +| 256 bytes | ~80 μs | Stable at 0% | Lowest achievable latency with this setup, still no risk of buffer overflow | +| 128 bytes | - | - | Results in error -- 128 bytes is too small for the current hardware configuration | Regarding the last row of the above table, the lowest `ReadSize` possible is determined by the size of the largest data frame produced by enabled devices @@ -307,16 +373,27 @@ shows that the hardware buffer does not accumulate data: ![](../../images/tutorials/tune-readsize/percent-used_256_lower-payload.png) -These two tables together demonstrates why it is impossible to recommend a +> [!TIP] +> - The only constraint on `ReadSize` is the lower limit as demonstrated in +> the example of tuning for `ReadSize` for a single 64-channel Intan chip. +> We only tested `ReadSize` values that are a power of 2, but `ReadSize` can +> be fine-tuned further to achieve even tighter latencies if necessary. +> - **As of OpenEphys.Onix1 0.7.0**: Although `ReadSize` can be set to any +> value by the user (besides the constraint described in the previous bullet +> point), the ONIX1 Bonsai package rounds this `ReadSize` to the nearest +> multiple of four and uses that value instead. For example, if you try to +> set `ReadSize` to 887, the software will use the value 888 instead. + +These two tables together demonstrate why it is impossible to recommend a single correct value for `ReadSize` that is adequate for all experiments. The diversity of experiments (in particular, the wide range at which they produce data) requires a range of `ReadSize` values. Last, in this tutorial, there was minimal computational load imposed by -the workflow itself. In most applications, some processing is performed on the -data to generate the feedback signal. It's important to take this into account -when tuning your system and potentially modifying the workflow to perform -computations on incoming data in order to account for the effect of +the workflow itself. In most applications, some processing is performed on the +data to generate the feedback signal. It's important to take this into account +when tuning your system and potentially modifying the workflow to perform +computations on incoming data in order to account for the effect of computational demand on closed loop performance. \ No newline at end of file From 9aa7847ab8b17a7c8427a9c81384c4c7b85bb301 Mon Sep 17 00:00:00 2001 From: Ceci Herbert Date: Wed, 17 Sep 2025 14:03:35 +0100 Subject: [PATCH 07/11] typos --- articles/tutorials/tune-readsize.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/articles/tutorials/tune-readsize.md b/articles/tutorials/tune-readsize.md index 086f6c75..888084c1 100644 --- a/articles/tutorials/tune-readsize.md +++ b/articles/tutorials/tune-readsize.md @@ -44,7 +44,7 @@ Key details about this process: terminate the acquisition session. `ReadSize` can be increased to avoid this situation. - As long as this situation is avoided, decreasing `ReadSize` means that ONIX - doesn't needs to produce as much data before the host can access it. This, + doesn't need to produce as much data before the host can access it. This, in effect, means software can start operating on data closer to the time that the data was produced, thus achieving lower-latency feedback-loops. @@ -101,7 +101,7 @@ So far, all this occurs on the host-side. Meanwhile, on the ONIX-side: buffer FIFO. The ONIX hardware buffer consists of 2GB of RAM that belongs to the acquisition hardware (it is _not_ RAM in the host computer) dedicated to temporarily storing data that is waiting to be transferred to the host. Data - is removed from front of the hardware buffer and transferred to the host + is removed from the front of the hardware buffer and transferred to the host once it's ready to accept more data. - If the memory is allocated on the host-side and the data transfer is initiated by the host API before any data is produced, ONIX transfers new From 4654c9a5dfc9a0d8ad5792c0c62f0b1c55eb3120 Mon Sep 17 00:00:00 2001 From: Ceci Herbert Date: Wed, 17 Sep 2025 14:10:24 +0100 Subject: [PATCH 08/11] brief edits for clarity --- articles/tutorials/tune-readsize.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/articles/tutorials/tune-readsize.md b/articles/tutorials/tune-readsize.md index 888084c1..3726238e 100644 --- a/articles/tutorials/tune-readsize.md +++ b/articles/tutorials/tune-readsize.md @@ -57,9 +57,9 @@ performance and eventually cause the hardware buffer to overflow, terminating acquisition. The goal of this tutorial is to tune StartAcquisition's `ReadSize` so that data flows from production to the software running on the host as quickly as possible by minimizing the amount of time that it sits idly in both -the ONIX hardware buffer and the API-allocated buffer. This provides software +the ONIX hardware buffer and the host computer's buffer. This provides software access to the data as close to when the data was produced as possible which -helps achieve lower latencies closed-loop feedback. +helps achieve lower latency closed-loop feedback. ### Technical Details @@ -195,7 +195,7 @@ memory for the creation of output data frames. Data is written to hardware as soon as an output frame has been created, so the effect on real-time performance is typically not as large as that of the `ReadSize` property. -To start,`ReadSize` is also set to 16384. Later in this tutorial, we'll examine +To start, `ReadSize` is also set to 16384. Later in this tutorial, we'll examine the effect of this value on real-time performance. ### Real-time Loop @@ -390,7 +390,7 @@ diversity of experiments (in particular, the wide range at which they produce data) requires a range of `ReadSize` values. Last, in this tutorial, there was minimal computational load imposed by -the workflow itself. In most applications, some processing is performed on the +the data processing workflow itself. In most applications, some processing is performed on the data to generate the feedback signal. It's important to take this into account when tuning your system and potentially modifying the workflow to perform computations on incoming data in order to account for the effect of From b8bad2385e588c33ca598a736ed65edbcc057695 Mon Sep 17 00:00:00 2001 From: cjsha Date: Wed, 17 Sep 2025 12:43:01 -0400 Subject: [PATCH 09/11] Add paragraph verifying closed-loop latency - how to measure latency using the devices that will be used during the actual experiment rather than loadtester --- articles/tutorials/tune-readsize.md | 40 ++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/articles/tutorials/tune-readsize.md b/articles/tutorials/tune-readsize.md index 3726238e..7507abf5 100644 --- a/articles/tutorials/tune-readsize.md +++ b/articles/tutorials/tune-readsize.md @@ -11,8 +11,8 @@ times can be achieved. > [!NOTE] > Performance will vary based on your computer's capabilities and your results -> might differ from those presented below. The computer used to create this tutorial -> has the following specs: +> might differ from those presented below. The computer used to create this +> tutorial has the following specs: > > - CPU: Intel i9-12900K > - RAM: 64 GB @@ -389,11 +389,37 @@ single correct value for `ReadSize` that is adequate for all experiments. The diversity of experiments (in particular, the wide range at which they produce data) requires a range of `ReadSize` values. -Last, in this tutorial, there was minimal computational load imposed by -the data processing workflow itself. In most applications, some processing is performed on the -data to generate the feedback signal. It's important to take this into account -when tuning your system and potentially modifying the workflow to perform -computations on incoming data in order to account for the effect of +Last, in this tutorial, there was minimal computational load imposed by the +workflow used in this tutorial. In most applications, some processing is +performed on the data to generate the feedback signal. It's important to take +this into account when tuning your system and potentially modifying the workflow +to perform computations on incoming data in order to account for the effect of computational demand on closed loop performance. +### Measuring Latency in Actual Experiment + +After tuning `ReadSize`, it is important to experimentally verify the latencies +using the actual devices in your experiment. For example, if your feedback +involves toggling ONIX's digital output (which in turn toggles a stimulation +device like a [Stimjim](https://github.com/open-ephys/stimjim) or a [RHS2116 +external +trigger](xref:OpenEphys.Onix1.ConfigureRhs2116Trigger.StimulusTrigger)), loop +that digital output signal back into one of ONIX's digital inputs. This enables +you to save when the feedback physically occurred. This can be used to measure +your feedback latency by taking the difference between the clock count when the +trigger condition occurred and the clock count when the feedback signal was +received by ONIX. + +You might wonder: why use the LoadTester device if I can measure latency using +the actual devices that I intend to use in my experiment? The benefit of the +LoadTester device is that you're able to collect at least tens of thousands of +latency samples to plot in a histogram in a short amount of time. Trying to use +digital I/O to take as many latency measurements in a similar amount of time can +render your latency measurements inaccurate for the actual experiment you intend +to perform. In particular, toggling digital inputs faster necessarily increases +the total data throughput of . If the data +throughput of `DigitalInputData` significantly exceeds what is required for your +experiment, the latency measurements will not reflect the latencies you will +experience during the actual experiment. + \ No newline at end of file From 094c20b5cf79b763f5ba59defc66cfb3a5d54b37 Mon Sep 17 00:00:00 2001 From: cjsha Date: Wed, 17 Sep 2025 12:51:32 -0400 Subject: [PATCH 10/11] fix references + minor edits --- articles/tutorials/tune-readsize.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/articles/tutorials/tune-readsize.md b/articles/tutorials/tune-readsize.md index 7507abf5..f13d54e8 100644 --- a/articles/tutorials/tune-readsize.md +++ b/articles/tutorials/tune-readsize.md @@ -403,12 +403,12 @@ using the actual devices in your experiment. For example, if your feedback involves toggling ONIX's digital output (which in turn toggles a stimulation device like a [Stimjim](https://github.com/open-ephys/stimjim) or a [RHS2116 external -trigger](xref:OpenEphys.Onix1.ConfigureRhs2116Trigger.StimulusTrigger)), loop -that digital output signal back into one of ONIX's digital inputs. This enables -you to save when the feedback physically occurred. This can be used to measure -your feedback latency by taking the difference between the clock count when the -trigger condition occurred and the clock count when the feedback signal was -received by ONIX. +trigger](xref:OpenEphys.Onix1.ConfigureRhs2116Trigger.TriggerSource)), +loop that digital output signal back into one of ONIX's digital inputs. This +enables you to save when the feedback physically occurs. This can be used to +measure your feedback latency by taking the difference between the clock count +when the trigger condition occurs and the clock count when the feedback signal +is received by ONIX. You might wonder: why use the LoadTester device if I can measure latency using the actual devices that I intend to use in my experiment? The benefit of the @@ -417,7 +417,7 @@ latency samples to plot in a histogram in a short amount of time. Trying to use digital I/O to take as many latency measurements in a similar amount of time can render your latency measurements inaccurate for the actual experiment you intend to perform. In particular, toggling digital inputs faster necessarily increases -the total data throughput of . If the data +the total data throughput of . If the data throughput of `DigitalInputData` significantly exceeds what is required for your experiment, the latency measurements will not reflect the latencies you will experience during the actual experiment. From 731f2224d062a71ff71dfb505b0dc1a50f4d3a0a Mon Sep 17 00:00:00 2001 From: cjsha Date: Thu, 18 Sep 2025 14:36:00 -0400 Subject: [PATCH 11/11] Add tips about variable data rates and background processes --- articles/tutorials/tune-readsize.md | 60 +++++++++++++++++------------ 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/articles/tutorials/tune-readsize.md b/articles/tutorials/tune-readsize.md index f13d54e8..15a09693 100644 --- a/articles/tutorials/tune-readsize.md +++ b/articles/tutorials/tune-readsize.md @@ -378,11 +378,23 @@ shows that the hardware buffer does not accumulate data: > the example of tuning for `ReadSize` for a single 64-channel Intan chip. > We only tested `ReadSize` values that are a power of 2, but `ReadSize` can > be fine-tuned further to achieve even tighter latencies if necessary. -> - **As of OpenEphys.Onix1 0.7.0**: Although `ReadSize` can be set to any -> value by the user (besides the constraint described in the previous bullet -> point), the ONIX1 Bonsai package rounds this `ReadSize` to the nearest -> multiple of four and uses that value instead. For example, if you try to -> set `ReadSize` to 887, the software will use the value 888 instead. +> - **As of OpenEphys.Onix1 0.7.0:** As long as you stay above the minimum +> mentioned in the previous bullet point, `ReadSize` can be set to any value +> by the user. The OpenEphys.Onix1 Bonsai package will round this `ReadSize` +> to the nearest multiple of four and uses that value instead. For example, +> if you try to set `ReadSize` to 887, the software will use the value 888 +> instead. +> - If you are using a data I/O operator that has capacity to produce data at +> various rates (like ), test your chosen +> `ReadSize` by configuring the load tester to produce data at the lower and +> upper limits that you expect data to be produced during your experiment. +> This will help ensure excess data doesn't accumulate in the hardware +> buffer and desired closed-loop latencies are maintained throughout the +> range of data throughput of these devices. +> - Running other processes that demand the CPU's attention might cause +> spurious spikes in data accumulation in the hardware buffer. Either reduce +> the amount other processes or test that they don't interfere with your +> experiment. These two tables together demonstrate why it is impossible to recommend a single correct value for `ReadSize` that is adequate for all experiments. The @@ -402,24 +414,24 @@ After tuning `ReadSize`, it is important to experimentally verify the latencies using the actual devices in your experiment. For example, if your feedback involves toggling ONIX's digital output (which in turn toggles a stimulation device like a [Stimjim](https://github.com/open-ephys/stimjim) or a [RHS2116 -external -trigger](xref:OpenEphys.Onix1.ConfigureRhs2116Trigger.TriggerSource)), -loop that digital output signal back into one of ONIX's digital inputs. This -enables you to save when the feedback physically occurs. This can be used to -measure your feedback latency by taking the difference between the clock count -when the trigger condition occurs and the clock count when the feedback signal -is received by ONIX. - -You might wonder: why use the LoadTester device if I can measure latency using -the actual devices that I intend to use in my experiment? The benefit of the -LoadTester device is that you're able to collect at least tens of thousands of -latency samples to plot in a histogram in a short amount of time. Trying to use -digital I/O to take as many latency measurements in a similar amount of time can -render your latency measurements inaccurate for the actual experiment you intend -to perform. In particular, toggling digital inputs faster necessarily increases -the total data throughput of . If the data -throughput of `DigitalInputData` significantly exceeds what is required for your -experiment, the latency measurements will not reflect the latencies you will -experience during the actual experiment. +external trigger](xref:OpenEphys.Onix1.ConfigureRhs2116Trigger.TriggerSource)), +you can loop that digital output signal back into one of ONIX's digital inputs +to measure when the feedback physically occurs. This can be used to measure your +feedback latency by taking the difference between the clock count when the +trigger condition occurs and the clock count when the feedback signal is +received by ONIX. + +You might wonder why you'd even use the LoadTester device if you can measure +latency using the actual devices that you intend to use in your experiment. The +benefit of the LoadTester device is that you're able to collect at least tens of +thousands of latency samples to plot in a histogram in a short amount of time. +Trying to use digital I/O to take as many latency measurements in a similar +amount of time can render your latency measurements inaccurate for the actual +experiment you intend to perform. In particular, toggling digital inputs faster +necessarily increases the total data throughput of +`DigitalInput`. If the data throughput of +`DigitalInput` significantly exceeds what is required for your experiment, +the latency measurements will not reflect the latencies you will experience +during the actual experiment. \ No newline at end of file