VirtualBox

Changeset 72588 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jun 17, 2018 6:28:31 PM (7 years ago)
Author:
vboxsync
Message:

DevATA: Reduce repeate RTThreadYield() calls on EMT on multicore+thread systems in a probably obsolete ATA busy hack. bugref:1960

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/DevATA.cpp

    r72587 r72588  
    4747#include <iprt/string.h>
    4848#ifdef IN_RING3
    49 # include <iprt/uuid.h>
     49# include <iprt/mem.h>
     50# include <iprt/mp.h>
    5051# include <iprt/semaphore.h>
    5152# include <iprt/thread.h>
    5253# include <iprt/time.h>
    53 # include <iprt/alloc.h>
     54# include <iprt/uuid.h>
    5455#endif /* IN_RING3 */
    5556#include <iprt/critsect.h>
     
    286287    RCPTRTYPE(uint8_t *)                pbIOBufferRC;
    287288
    288     /** Counter for number of busy status seen in GC/R0 in a row. */
    289     uint32_t                            cBusyStatusHack;
    290 
    291289    /*
    292290     * No data that is part of the saved state after this point!!!!!
    293291     */
    294292
    295     /* Release statistics: number of ATA DMA commands. */
     293    /** Counter for number of busy status seen in R3 in a row. */
     294    uint8_t                             cBusyStatusHackR3;
     295    /** Counter for number of busy status seen in GC/R0 in a row. */
     296    uint8_t                             cBusyStatusHackRZ;
     297    /** Defines the R3 yield rate by a mask (power of 2 minus one).
     298     * Lower is more agressive. */
     299    uint8_t                             cBusyStatusHackR3Rate;
     300    /** Defines the RZ yield rate by number of status requests before returning
     301     * to ring-3 and yielding there.  Lower is more agressive. */
     302    uint8_t                             cBusyStatusHackRZRate;
     303
     304    /** Release statistics: number of ATA DMA commands. */
    296305    STAMCOUNTER                         StatATADMA;
    297     /* Release statistics: number of ATA PIO commands. */
     306    /** Release statistics: number of ATA PIO commands. */
    298307    STAMCOUNTER                         StatATAPIO;
    299     /* Release statistics: number of ATAPI PIO commands. */
     308    /** Release statistics: number of ATAPI PIO commands. */
    300309    STAMCOUNTER                         StatATAPIDMA;
    301     /* Release statistics: number of ATAPI PIO commands. */
     310    /** Release statistics: number of ATAPI PIO commands. */
    302311    STAMCOUNTER                         StatATAPIPIO;
    303312#ifdef VBOX_INSTRUMENT_DMA_WRITES
    304     /* Release statistics: number of DMA sector writes and the time spent. */
     313    /** Release statistics: number of DMA sector writes and the time spent. */
    305314    STAMPROFILEADV                      StatInstrVDWrites;
    306315#endif
     316    /** Release statistics: Profiling RTThreadYield calls during status polling. */
     317    STAMPROFILEADV                      StatStatusYields;
    307318
    308319    /** Statistics: number of read operations and the time spent reading. */
     
    44694480            {
    44704481#ifdef IN_RING3
    4471                 s->cBusyStatusHack = 0;
     4482                /* @bugref{1960}: Don't yield all the time, unless it's a reset (can be tricky). */
     4483                bool fYield = (s->cBusyStatusHackR3++ & s->cBusyStatusHackR3Rate) == 0
     4484                            || pCtl->fReset;
     4485
    44724486                ataR3LockLeave(pCtl);
    44734487
    4474 # ifndef RT_OS_WINDOWS
    44754488                /*
    4476                  * The thread might be stuck in an I/O operation
    4477                  * due to a high I/O load on the host. (see @bugref{3301})
    4478                  * To perform the reset successfully
    4479                  * we interrupt the operation by sending a signal to the thread
    4480                  * if the thread didn't responded in 10ms.
    4481                  * This works only on POSIX hosts (Windows has a CancelSynchronousIo function which
    4482                  * does the same but it was introduced with Vista) but so far
    4483                  * this hang was only observed on Linux and Mac OS X.
     4489                 * The thread might be stuck in an I/O operation due to a high I/O
     4490                 * load on the host (see @bugref{3301}).  To perform the reset
     4491                 * successfully we interrupt the operation by sending a signal to
     4492                 * the thread if the thread didn't responded in 10ms.
     4493                 *
     4494                 * This works only on POSIX hosts (Windows has a CancelSynchronousIo
     4495                 * function which does the same but it was introduced with Vista) but
     4496                 * so far this hang was only observed on Linux and Mac OS X.
    44844497                 *
    44854498                 * This is a workaround and needs to be solved properly.
     
    44884501                {
    44894502                    uint64_t u64ResetTimeStop = RTTimeMilliTS();
    4490 
    4491                     if ((u64ResetTimeStop - pCtl->u64ResetTime) >= 10)
     4503                    if (u64ResetTimeStop - pCtl->u64ResetTime >= 10)
    44924504                    {
    44934505                        LogRel(("PIIX3 ATA LUN#%d: Async I/O thread probably stuck in operation, interrupting\n", s->iLUN));
    44944506                        pCtl->u64ResetTime = u64ResetTimeStop;
     4507# ifndef RT_OS_WINDOWS /* We've got this API on windows, but it doesn't necessarily interrupt I/O. */
    44954508                        RTThreadPoke(pCtl->AsyncIOThread);
     4509# endif
     4510                        Assert(fYield);
    44964511                    }
    44974512                }
    4498 # endif
    4499 
    4500                 RTThreadYield();
     4513
     4514                if (fYield)
     4515                {
     4516                    STAM_REL_PROFILE_ADV_START(&s->StatStatusYields, a);
     4517                    RTThreadYield();
     4518                    STAM_REL_PROFILE_ADV_STOP(&s->StatStatusYields, a);
     4519                }
     4520                ASMNopPause();
    45014521
    45024522                ataR3LockEnter(pCtl);
     
    45084528                 * especially on SMP systems where we don't gain much by
    45094529                 * yielding the CPU to someone else. */
    4510                 if (++s->cBusyStatusHack >= 20)
     4530                if (++s->cBusyStatusHackRZ >= s->cBusyStatusHackRZRate)
    45114531                {
    4512                     s->cBusyStatusHack = 0;
     4532                    s->cBusyStatusHackRZ = 0;
     4533                    s->cBusyStatusHackR3 = 0; /* Forces a yield. */
    45134534                    return VINF_IOM_R3_IOPORT_READ;
    45144535                }
     
    45164537            }
    45174538            else
    4518                 s->cBusyStatusHack = 0;
     4539            {
     4540                s->cBusyStatusHackRZ = 0;
     4541                s->cBusyStatusHackR3 = 0;
     4542            }
    45194543            ataUnsetIRQ(s);
    45204544            break;
     
    64966520            LogRel(("PIIX3 ATA: LUN#%d: TRIM enabled\n", pIf->iLUN));
    64976521    }
     6522
     6523    /*
     6524     * Check if SMP system to adjust the agressiveness of the busy yield hack (@bugref{1960}).
     6525     *
     6526     * The hack is an ancient (2006?) one for dealing with UNI CPU systems where EMT
     6527     * would potentially monopolise the CPU and starve I/O threads.  It causes the EMT to
     6528     * yield it's timeslice if the guest polls the status register during I/O.  On modern
     6529     * multicore and multithreaded systems, yielding EMT too often may have adverse
     6530     * effects (slow grub) so we aim at avoiding repeating the yield there too often.
     6531     */
     6532    RTCPUID cCpus = RTMpGetOnlineCount();
     6533    if (cCpus <= 1)
     6534    {
     6535        pIf->cBusyStatusHackR3Rate = 1;
     6536        pIf->cBusyStatusHackRZRate = 8;
     6537    }
     6538    else if (cCpus <= 2)
     6539    {
     6540        pIf->cBusyStatusHackR3Rate = 3;
     6541        pIf->cBusyStatusHackRZRate = 20;
     6542    }
     6543    else if (cCpus <= 4)
     6544    {
     6545        pIf->cBusyStatusHackR3Rate = 15;
     6546        pIf->cBusyStatusHackRZRate = 32;
     6547    }
     6548    else
     6549    {
     6550        pIf->cBusyStatusHackR3Rate = 127;
     6551        pIf->cBusyStatusHackRZRate = 128;
     6552    }
     6553
    64986554    return rc;
    64996555}
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