VirtualBox

Changeset 88063 in vbox


Ignore:
Timestamp:
Mar 9, 2021 9:48:07 PM (4 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
143197
Message:

DevHDA: Tweaked the AIO output scheduling a little, ignoring uTimerHz and instead using a new initial delay parameter (default to 12 ms). The AIO thread is always woken up after the delay (actually, that's been the case since r143099 (trunk) / r143109 (6.1)). bugref:9890

Location:
trunk/src/VBox/Devices/Audio
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Audio/DevHDA.cpp

    r88028 r88063  
    14441444                    /* Avoid going through the timer here by calling the stream's timer function directly.
    14451445                     * Should speed up starting the stream transfers. */
    1446                     hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3);
     1446                    uint64_t tsNow = hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3);
     1447
     1448                    hdaR3StreamMarkStarted(pDevIns, pThis, pStreamShared, tsNow);
    14471449                }
    14481450                else
     
    14581460                    /* Reset the period. */
    14591461                    hdaR3StreamPeriodReset(&pStreamShared->State.Period);
     1462
     1463                    hdaR3StreamMarkStopped(pStreamShared);
    14601464                }
    14611465            }
     
    35193523            hdaR3StreamRegisterDMAHandlers(pThis, pStreamShared);
    35203524#endif
    3521             if (hdaR3StreamTransferIsScheduled(pStreamShared, PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer)))
     3525            /** @todo r=bird: This can go wrong if the state saving happened exactly when
     3526             *        the timer expired.  See comparison in
     3527             *        hdaR3StreamTransferIsScheduled.   I've decided to just do this
     3528             *        unconditionally as that fixes the issue and simplifies the
     3529             *        hdaR3StreamMarkStarted.  Also, I don't really get why this check is
     3530             *        necessary at all. */
     3531            /*if (hdaR3StreamTransferIsScheduled(pStreamShared, PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer))) */
    35223532            {
    35233533                /* Avoid going through the timer here by calling the stream's timer function directly.
    35243534                 * Should speed up starting the stream transfers. */
    3525                 hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3);
     3535                uint64_t tsNow = hdaR3StreamTimerMain(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3);
     3536
     3537                hdaR3StreamMarkStarted(pDevIns, pThis, pStreamShared, tsNow);
    35263538            }
    35273539
     
    46074619     * Validate and read configuration.
    46084620     */
    4609     PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "BufSizeInMs|BufSizeOutMs|TimerHz|PosAdjustEnabled|PosAdjustFrames|TransferHeuristicsEnabled|DebugEnabled|DebugPathOut", "");
     4621    PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
     4622                                  "BufSizeInMs"
     4623                                  "|BufSizeOutMs"
     4624                                  "|InitialDelayMs"
     4625                                  "|TimerHz"
     4626                                  "|PosAdjustEnabled"
     4627                                  "|PosAdjustFrames"
     4628                                  "|TransferHeuristicsEnabled"
     4629                                  "|DebugEnabled"
     4630                                  "|DebugPathOut",
     4631                                  "");
    46104632
    46114633    /* Note: Error checking of this value happens in hdaR3StreamSetUp(). */
     
    46284650    if (pThis->uTimerHz != HDA_TIMER_HZ_DEFAULT)
    46294651        LogRel(("HDA: Using custom device timer rate (%RU16Hz)\n", pThis->uTimerHz));
     4652
     4653    /** @devcfgm{hda,InitialDelayMs,uint16_t,0,256,12,ms}
     4654     * How long to delay when a stream starts before engaging the asynchronous I/O
     4655     * thread from the DMA timer callback.  Because it's used from the DMA timer
     4656     * callback, it will implicitly be rounded up to the next timer period.
     4657     * This is for adding a little host scheduling leeway into the playback. */
     4658    rc = pHlp->pfnCFGMQueryU16Def(pCfg, "InitialDelayMs", &pThis->msInitialDelay, 12);
     4659    if (RT_FAILURE(rc))
     4660         return PDMDEV_SET_ERROR(pDevIns, rc, N_("HDA configuration error: failed to read 'InitialDelayMs' as uint16_t"));
     4661    if (pThis->msInitialDelay > 256)
     4662        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
     4663                                   N_("HDA configuration error: Out of range: 0 <= InitialDelayMs < 256: %u"), pThis->msInitialDelay);
    46304664
    46314665    rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "PosAdjustEnabled", &pThis->fPosAdjustEnabled, true);
  • trunk/src/VBox/Devices/Audio/DevHDA.h

    r87861 r88063  
    127127    uint8_t                 bPadding1;
    128128#endif
     129    uint8_t                 bPadding2;
    129130    /** The device timer Hz rate. Defaults to HDA_TIMER_HZ_DEFAULT. */
    130131    uint16_t                uTimerHz;
     132    /** Number of milliseconds to delay kicking off the AIO when a stream starts.
     133     * @sa InitialDelayMs config value.  */
     134    uint16_t                msInitialDelay;
    131135    /** Buffer size (in ms) of the internal input FIFO buffer.
    132136     *  The actual buffer size in bytes will depend on the actual stream configuration. */
     
    135139     *  The actual buffer size in bytes will depend on the actual stream configuration. */
    136140    uint16_t                cbCircBufOutMs;
    137     /** Padding for alignment. */
    138     uint16_t                u16Padding3;
     141    uint16_t                au16Padding3[3];
    139142    /** Last updated wall clock (WALCLK) counter. */
    140143    uint64_t                u64WalClk;
  • trunk/src/VBox/Devices/Audio/HDAStream.cpp

    r88028 r88063  
    699699         *       channels we don't support / need to save space.
    700700         */
    701         uint32_t cbCircBuf = PDMAudioPropsMilliToBytes(&pCfg->Props,
    702                                                      RT_MS_1SEC * 6 / RT_MIN(uTransferHz, pStreamShared->State.uTimerIoHz));
     701        uint32_t msCircBuf = RT_MS_1SEC * 6 / RT_MIN(uTransferHz, pStreamShared->State.uTimerIoHz);
     702        msCircBuf = RT_MAX(msCircBuf, pThis->msInitialDelay + RT_MS_1SEC * 6 / uTransferHz);
     703
     704        uint32_t cbCircBuf = PDMAudioPropsMilliToBytes(&pCfg->Props, msCircBuf);
    703705        LogRel2(("HDA: Stream #%RU8 default ring buffer size is %RU32 bytes / %RU64 ms\n",
    704706                 uSD, cbCircBuf, PDMAudioPropsBytesToMilli(&pCfg->Props, cbCircBuf)));
     
    805807    pStreamShared->State.tsLastTransferNs = 0;
    806808    pStreamShared->State.tsLastReadNs     = 0;
     809    pStreamShared->State.tsAioDelayEnd    = UINT64_MAX;
     810    pStreamShared->State.tsStart          = 0;
    807811
    808812    RT_ZERO(pStreamShared->State.BDLE);
     
    905909}
    906910
     911/**
     912 * Marks the stream as started.
     913 *
     914 * Used after the stream has been enabled and the DMA timer has been armed.
     915 */
     916void hdaR3StreamMarkStarted(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, uint64_t tsNow)
     917{
     918    pStreamShared->State.tsLastReadNs  = RTTimeNanoTS();
     919    pStreamShared->State.tsStart       = tsNow;
     920    pStreamShared->State.tsAioDelayEnd = tsNow + PDMDevHlpTimerFromMilli(pDevIns, pStreamShared->hTimer, pThis->msInitialDelay);
     921    Log3Func(("#%u: tsStart=%RU64 tsAioDelayEnd=%RU64 tsLastReadNs=%RU64\n", pStreamShared->u8SD,
     922              pStreamShared->State.tsStart, pStreamShared->State.tsAioDelayEnd, pStreamShared->State.tsLastReadNs));
     923
     924}
     925
     926/**
     927 * Marks the stream as stopped.
     928 */
     929void hdaR3StreamMarkStopped(PHDASTREAM pStreamShared)
     930{
     931    Log3Func(("#%u\n", pStreamShared->u8SD));
     932    pStreamShared->State.tsAioDelayEnd = UINT64_MAX;
     933}
     934
     935
    907936#if 0 /* Not used atm. */
    908937static uint32_t hdaR3StreamGetPosition(PHDASTATE pThis, PHDASTREAM pStreamShared)
     
    10131042            }
    10141043
     1044            /** @todo r=bird: how can this be right?   */
    10151045            if (pStreamShared->State.tsTransferNext > tsNow)
    10161046            {
     
    17041734 * The stream's main function when called by the timer.
    17051735 *
    1706  * Note: This function also will be called without timer invocation
    1707  *       when starting (enabling) the stream to minimize startup latency.
    1708  *
     1736 * @note This function also will be called without timer invocation when
     1737 *       starting (enabling) the stream to minimize startup latency.
     1738 *
     1739 * @returns Current timer time if the timer is enabled, otherwise zero.
    17091740 * @param   pDevIns         The device instance.
    17101741 * @param   pThis           The shared HDA device state.
     
    17131744 * @param   pStreamR3       HDA stream to update (ring-3 bits).
    17141745 */
    1715 void hdaR3StreamTimerMain(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
    1716                           PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3)
     1746uint64_t hdaR3StreamTimerMain(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
     1747                              PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3)
    17171748{
    17181749    Assert(PDMDevHlpCritSectIsOwner(pDevIns, &pThis->CritSect));
     
    17351766        const bool     fTimerScheduled = hdaR3StreamTransferIsScheduled(pStreamShared, tsNow);
    17361767
    1737         uint64_t tsTransferNext  = 0;
     1768        /** @todo r=bird: This is a waste of time if the timer is called at a
     1769         *        constant rate.  We can just calculate it here.  */
     1770        uint64_t tsTransferNext;
    17381771        if (fTimerScheduled)
    17391772        {
     
    17491782        hdaR3TimerSet(pDevIns, pStreamShared, tsTransferNext,
    17501783                      true /*fForce*/, tsNow);
    1751     }
    1752     else
    1753         Log3Func(("[SD%RU8] fSinksActive=%RTbool\n", uSD, fSinkActive));
     1784        return tsNow;
     1785    }
     1786
     1787    Log3Func(("[SD%RU8] fSinksActive=%RTbool\n", uSD, fSinkActive));
     1788    return 0;
    17541789}
    17551790
     
    17971832    if (hdaGetDirFromSD(pStreamShared->u8SD) == PDMAUDIODIR_OUT) /* Output (SDO). */
    17981833    {
    1799         bool fDoRead = fInTimer; /* Whether to read from the HDA stream or not. */
    1800 
    18011834        /*
    18021835         * Do DMA work.
    18031836         */
     1837        bool fDoRead = false; /* Whether to push data down the driver stack or not.  */
    18041838# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    18051839        if (fInTimer)
     
    18251859
    18261860            /* Do the DMA transfer. */
     1861            uint64_t const offWriteBefore = pStreamR3->State.offWrite;
    18271862            rc2 = hdaR3StreamTransfer(pDevIns, pThis, pThisCC, pStreamShared, pStreamR3, cbStreamFree);
    18281863            AssertRC(rc2);
    1829 
    1830             /* Never read yet? Set initial timestamp. */
    1831             if (pStreamShared->State.tsLastReadNs == 0)
    1832                 pStreamShared->State.tsLastReadNs = tsNowNs;
    18331864
    18341865            /*
    18351866             * Push data to down thru the mixer to and to the host drivers?
    18361867             *
    1837              * This is generally done at the rate given by cMsSchedulingHint,
    1838              * however we must also check available DMA buffer space.  There
    1839              * should be at least two periodic transfer units worth of space
    1840              * available now.
     1868             * We initially delay this by pThis->msInitialDelay, but after than we'll
     1869             * kick the AIO thread every time we've put more data in the buffer (which is
     1870             * every time) as the host audio device needs to get data in a timely manner.
     1871             *
     1872             * (We used to try only wake up the AIO thread according to pThis->uIoTimer
     1873             * and host wall clock, but that meant we would miss a wakup after the DMA
     1874             * timer was called a little late or if TM entered into catch-up mode.)
    18411875             */
    1842             Assert(tsNowNs >= pStreamShared->State.tsLastReadNs);
    1843             /** @todo convert cMsSchedulingHint to nano seconds and save a div.  */
    1844             const uint64_t msDelta = (tsNowNs - pStreamShared->State.tsLastReadNs) / RT_NS_1MS;
    1845             cbStreamFree = hdaR3StreamGetFree(pStreamR3);
    1846             if (   cbStreamFree < pStreamShared->State.cbTransferSize * 2
    1847                 || msDelta >= pStreamShared->State.Cfg.Device.cMsSchedulingHint)
     1876            if (!pStreamShared->State.tsAioDelayEnd)
     1877                fDoRead = pStreamR3->State.offWrite > offWriteBefore
     1878                       || hdaR3StreamGetFree(pStreamR3) < pStreamShared->State.cbTransferSize * 2;
     1879            else if (PDMDevHlpTimerGet(pDevIns, pStreamShared->hTimer) >= pStreamShared->State.tsAioDelayEnd)
     1880            {
     1881                Log3Func(("Initial delay done: Passed tsAioDelayEnd.\n"));
     1882                pStreamShared->State.tsAioDelayEnd = 0;
    18481883                fDoRead = true;
    1849 
    1850             Log3Func(("msDelta=%RU64 (vs %u) cbStreamFree=%#x (vs %#x) => fDoRead=%RTbool\n", msDelta,
     1884            }
     1885            else if (hdaR3StreamGetFree(pStreamR3) < pStreamShared->State.cbTransferSize * 2)
     1886            {
     1887                Log3Func(("Initial delay done: Passed running short on buffer.\n"));
     1888                pStreamShared->State.tsAioDelayEnd = 0;
     1889                fDoRead = true;
     1890            }
     1891            else
     1892            {
     1893                Log3Func(("Initial delay pending...\n"));
     1894                fDoRead = false;
     1895            }
     1896
     1897            Log3Func(("msDelta=%RU64 (vs %u) cbStreamFree=%#x (vs %#x) => fDoRead=%RTbool\n",
     1898                      (tsNowNs - pStreamShared->State.tsLastReadNs) / RT_NS_1MS,
    18511899                      pStreamShared->State.Cfg.Device.cMsSchedulingHint, cbStreamFree,
    18521900                      pStreamShared->State.cbTransferSize * 2, fDoRead));
     
    18601908                AssertRC(rc2);
    18611909# endif
    1862                 /* Update last read timestamp so that we know when to run next. */
     1910                /* Update last read timestamp for logging/debugging. */
    18631911                pStreamShared->State.tsLastReadNs = tsNowNs;
    18641912            }
    18651913        }
    18661914
     1915        /*
     1916         * <Missing Description>
     1917         */
    18671918# ifdef VBOX_WITH_AUDIO_HDA_ASYNC_IO
    18681919        if (!fInTimer) /* In async I/O thread */
  • trunk/src/VBox/Devices/Audio/HDAStream.h

    r87989 r88063  
    166166     *  because reading / processing will be done in a separate stream. */
    167167    uint64_t                tsLastReadNs;
     168
     169    /** This is set to the timer clock time when the msInitialDelay period is over.
     170     * Once reached, this is set to zero to avoid unnecessary time queries. */
     171    uint64_t                tsAioDelayEnd;
     172    /** The start time for the playback (on the timer clock). */
     173    uint64_t                tsStart;
    168174} HDASTREAMSTATE;
    169175AssertCompileSizeAlignment(HDASTREAMSTATE, 8);
     
    291297                                     PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, uint8_t uSD);
    292298int                 hdaR3StreamEnable(PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3, bool fEnable);
     299void                hdaR3StreamMarkStarted(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTREAM pStreamShared, uint64_t tsNow);
     300void                hdaR3StreamMarkStopped(PHDASTREAM pStreamShared);
     301
    293302void                hdaR3StreamSetPositionAdd(PHDASTREAM pStreamShared, PPDMDEVINS pDevIns, PHDASTATE pThis, uint32_t uToAdd);
    294 void                hdaR3StreamTimerMain(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
     303uint64_t            hdaR3StreamTimerMain(PPDMDEVINS pDevIns, PHDASTATE pThis, PHDASTATER3 pThisCC,
    295304                                         PHDASTREAM pStreamShared, PHDASTREAMR3 pStreamR3);
    296305bool                hdaR3StreamTransferIsScheduled(PHDASTREAM pStreamShared, uint64_t tsNow);
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette