diff --git a/docs/source/components/device.rst b/docs/source/components/device.rst index 8b13875ff..c7b318d07 100644 --- a/docs/source/components/device.rst +++ b/docs/source/components/device.rst @@ -40,26 +40,58 @@ If you want to use multiple devices on a host, check :ref:`Multiple DepthAI per Device queues ############# -After initializing the device, one has to initialize the input/output queues as well. You can create an input queue with -:code:`device.getInputQueue("input_name")` and output queue with :code:`device.getOutputQueue("output_name")`. - - -When you define an output queue, the device can write to it at any point in time, and the host can read from it at any point in time. -There might be a cases when the host is reading very fast from the queue, and the queue, no matter its size, will stay empty most of -the time. But as we add things on the host side (additional processing, analysis etc), it may happen that the device will be writing to -the queue faster than the host can read from it. And then the packets in the queue will start to add up - and both maxSize and blocking -flags determine the behavior of the queue in this case. - -By default, the queue is blocking and its size is 30, so the device will put -30 packets at most, and when the limit is reached, it will hang on queue put call and wait until it can successfully complete this -call (so, waits for the host to consume the packet before putting a new one). Making the queue non-blocking will change its behavior -in this situation - instead of waiting, it will discard the oldest packet and add the new one, and then continue it's processing -loop (so it won't get blocked). maxSize determines the size of the queue and also -helps to control the memory usage - if the packet have 5MB of data, and the queue size is 30, this queue effectively stores -150MB of data in memory (the packets can also get really big, for instance a single 4K NV12 encoded frame takes about ~12MB). -Decreasing the queue size to 1 and setting non-blocking behavior will effectively mean "I only want the latest packet from the queue". - -The size and behavior of the queue can be modified after the initialization by calling :code:`queue.setBlocking()` and :code:`queue.setMaxSize()`. +After initializing the device, one has to initialize the input/output queues as well. + +.. code-block:: python + + outputQueue = device.getOutputQueue("output_name") + inputQueue = device.getInputQueue("input_name") + +When you define an output queue, the device can push new messages to it at any point in time, and the host can read from it at any point in time. +Usually, when the host is reading very fast from the queue, the queue (regardless of its size) will stay empty most of +the time. But as we add things on the host side (additional processing, analysis, etc), it may happen that the device will be writing to +the queue faster than the host can read from it. And then the messages in the queue will start to add up - and both maxSize and blocking +flags determine the behavior of the queue in this case. You can set these flags with: + +.. code-block:: python + + # When initializing the queue + queue = device.getOutputQueue(name="name", maxSize=5, blocking=False) + + # Or afterwards + queue.setMaxSize(10) + queue.setBlocking(True) + +Blocking behaviour +****************** + +By default, queues are **blocking** and their size is **30**, so when the device fills up a queue and when the limit is +reached, any additional messages from the device will be blocked and the library will wait until it can add new messages to the queue. +It will wait for the host to consume (eg. :code:`queue.get()`) a message before putting a new one into the queue. + +.. note:: + After the host queue gets filled up, the XLinkOut.input queue on the device will start filling up. If that queue is + set to blocking, other nodes that are sending messages to it will have to wait as well. This is a usual cause for a + blocked pipeline, where one of the queues isn't emptied in timely manner and the rest of the pipeline waits for it + to be empty again. + +Non-Blocking behaviour +********************** +Making the queue non-blocking will change the behavior in the situation described above - instead of waiting, the library will discard +the oldest message and add the new one to the queue, and then continue its processing loop (so it won't get blocked). +:code:`maxSize` determines the size of the queue and it also helps to control memory usage. + +For example, if a message has 5MB of data, and the queue size is 30, this queue can effectively store +up to 150MB of data in the memory on the host (the messages can also get really big, for instance, a single 4K NV12 encoded frame takes about ~12MB). + +Some additional information +*************************** + +- Decreasing the queue size to 1 and setting non-blocking behavior will effectively mean "I only want the latest packet from the queue". +- Queues are thread-safe - they can be accessed from any thread. +- Queues are created such that each queue is its own thread which takes care of receiving, serializing/deserializing, and sending the messages forward (same for input/output queues). +- The :code:`Device` object isn't fully thread-safe. Some RPC calls (eg. :code:`getLogLevel`, :code:`setLogLevel`, :code:`getDdrMemoryUsage`) will get thread-safe once the mutex is set in place (right now there could be races). + Reference #########