VirtualBox

Changeset 62001 in vbox for trunk


Ignore:
Timestamp:
Jul 4, 2016 12:07:24 PM (9 years ago)
Author:
vboxsync
Message:

DevOHCI: bugref:8125: cache for the guest memory reads

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/USB/DevOHCI.cpp

    r59875 r62001  
    9393#include <iprt/semaphore.h>
    9494#include <iprt/critsect.h>
     95#include <iprt/param.h>
    9596#ifdef IN_RING3
    9697# include <iprt/alloca.h>
     
    102103#include "VBoxDD.h"
    103104
     105
     106#define VBOX_WITH_OHCI_PHYS_READ_CACHE
     107//#define VBOX_WITH_OHCI_PHYS_READ_STATS
    104108
    105109/*********************************************************************************************************************************
     
    243247typedef OHCILOAD *POHCILOAD;
    244248
     249#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     250typedef struct OHCIPAGECACHE
     251{
     252    /** Last read physical page address. */
     253    RTGCPHYS            GCPhysReadCacheAddr;
     254    /** Copy of last read physical page. */
     255    uint8_t             au8PhysReadCache[PAGE_SIZE];
     256} OHCIPAGECACHE, *POHCIPAGECACHE;
     257#endif
    245258
    246259/**
     
    398411    /** Critical section to synchronize the framer and URB completion handler. */
    399412    RTCRITSECT                 CritSect;
     413#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     414    /** Last read physical page for caching ED reads in the framer thread. */
     415    R3PTRTYPE(POHCIPAGECACHE)  pCacheED;
     416    /** Last read physical page for caching TD reads in the framer thread. */
     417    R3PTRTYPE(POHCIPAGECACHE)  pCacheTD;
     418#endif
    400419
    401420} OHCI;
     
    815834static void                 ohciBusResume(POHCI ohci, bool fHardware);
    816835static void                 ohciBusStop(POHCI pThis);
     836#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     837static void                 ohciPhysReadCacheClear(POHCIPAGECACHE pPageCache);
     838#endif
    817839
    818840static DECLCALLBACK(void)   ohciRhXferCompletion(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb);
     
    11781200    pThis->fno = 0;
    11791201
     1202#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     1203    ohciPhysReadCacheClear(pThis->pCacheED);
     1204    ohciPhysReadCacheClear(pThis->pCacheTD);
     1205#endif
     1206
    11801207    /*
    11811208     * If this is a hardware reset, we will initialize the root hub too.
     
    12381265#ifdef IN_RING3
    12391266
     1267#ifdef VBOX_WITH_OHCI_PHYS_READ_STATS
     1268struct DescReadStats
     1269{
     1270    uint32_t cReads;
     1271    uint32_t cPageChange;
     1272    uint32_t cMinReadsPerPage;
     1273    uint32_t cMaxReadsPerPage;
     1274
     1275    uint32_t cReadsLastPage;
     1276    uint32_t u32LastPageAddr;
     1277};
     1278
     1279struct PhysReadStats
     1280{
     1281    struct DescReadStats ed;
     1282    struct DescReadStats td;
     1283    struct DescReadStats all;
     1284
     1285    uint32_t cCrossReads;
     1286    uint32_t cCacheReads;
     1287    uint32_t cPageReads;
     1288};
     1289
     1290static struct PhysReadStats physReadStats;
     1291
     1292static void descReadStatsReset(struct DescReadStats *p)
     1293{
     1294    p->cReads = 0;
     1295    p->cPageChange = 0;
     1296    p->cMinReadsPerPage = UINT32_MAX;
     1297    p->cMaxReadsPerPage = 0;
     1298
     1299    p->cReadsLastPage = 0;
     1300    p->u32LastPageAddr = 0;
     1301}
     1302
     1303static void physReadStatsReset(struct PhysReadStats *p)
     1304{
     1305    descReadStatsReset(&p->ed);
     1306    descReadStatsReset(&p->td);
     1307    descReadStatsReset(&p->all);
     1308
     1309    p->cCrossReads = 0;
     1310    p->cCacheReads = 0;
     1311    p->cPageReads = 0;
     1312}
     1313
     1314static void physReadStatsUpdateDesc(struct DescReadStats *p, uint32_t u32Addr)
     1315{
     1316    const uint32_t u32PageAddr = u32Addr & ~UINT32_C(0xFFF);
     1317
     1318    ++p->cReads;
     1319
     1320    if (p->u32LastPageAddr == 0)
     1321    {
     1322       /* First call. */
     1323       ++p->cReadsLastPage;
     1324       p->u32LastPageAddr = u32PageAddr;
     1325    }
     1326    else if (u32PageAddr != p->u32LastPageAddr)
     1327    {
     1328       /* New page. */
     1329       ++p->cPageChange;
     1330
     1331       p->cMinReadsPerPage = RT_MIN(p->cMinReadsPerPage, p->cReadsLastPage);
     1332       p->cMaxReadsPerPage = RT_MAX(p->cMaxReadsPerPage, p->cReadsLastPage);;
     1333
     1334       p->cReadsLastPage = 1;
     1335       p->u32LastPageAddr = u32PageAddr;
     1336    }
     1337    else
     1338    {
     1339        /* Read on the same page. */
     1340       ++p->cReadsLastPage;
     1341    }
     1342}
     1343
     1344static void physReadStatsPrint(struct PhysReadStats *p)
     1345{
     1346    p->ed.cMinReadsPerPage = RT_MIN(p->ed.cMinReadsPerPage, p->ed.cReadsLastPage);
     1347    p->ed.cMaxReadsPerPage = RT_MAX(p->ed.cMaxReadsPerPage, p->ed.cReadsLastPage);;
     1348   
     1349    p->td.cMinReadsPerPage = RT_MIN(p->td.cMinReadsPerPage, p->td.cReadsLastPage);
     1350    p->td.cMaxReadsPerPage = RT_MAX(p->td.cMaxReadsPerPage, p->td.cReadsLastPage);;
     1351   
     1352    p->all.cMinReadsPerPage = RT_MIN(p->all.cMinReadsPerPage, p->all.cReadsLastPage);
     1353    p->all.cMaxReadsPerPage = RT_MAX(p->all.cMaxReadsPerPage, p->all.cReadsLastPage);;
     1354
     1355    LogRel(("PHYSREAD:\n"
     1356            "  ED: %d, %d, %d/%d\n"
     1357            "  TD: %d, %d, %d/%d\n"
     1358            " ALL: %d, %d, %d/%d\n"
     1359            "   C: %d, %d, %d\n"
     1360            "",
     1361            p->ed.cReads, p->ed.cPageChange, p->ed.cMinReadsPerPage, p->ed.cMaxReadsPerPage,
     1362            p->td.cReads, p->td.cPageChange, p->td.cMinReadsPerPage, p->td.cMaxReadsPerPage,
     1363            p->all.cReads, p->all.cPageChange, p->all.cMinReadsPerPage, p->all.cMaxReadsPerPage,
     1364            p->cCrossReads, p->cCacheReads, p->cPageReads
     1365          ));
     1366
     1367    physReadStatsReset(p);
     1368}
     1369#endif /* VBOX_WITH_OHCI_PHYS_READ_STATS */
     1370
     1371#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     1372static POHCIPAGECACHE ohciPhysReadCacheAlloc(void)
     1373{
     1374    return (POHCIPAGECACHE)RTMemAlloc(sizeof(OHCIPAGECACHE));
     1375}
     1376
     1377static void ohciPhysReadCacheFree(POHCIPAGECACHE pPageCache)
     1378{
     1379    RTMemFree(pPageCache);
     1380}
     1381
     1382static void ohciPhysReadCacheClear(POHCIPAGECACHE pPageCache)
     1383{
     1384    pPageCache->GCPhysReadCacheAddr = NIL_RTGCPHYS;
     1385}
     1386
     1387static void ohciPhysReadCacheRead(POHCI pThis, POHCIPAGECACHE pPageCache, RTGCPHYS GCPhys, void *pvBuf, size_t cbBuf)
     1388{
     1389    const RTGCPHYS PageAddr = PAGE_ADDRESS(GCPhys);
     1390
     1391    if (PageAddr == PAGE_ADDRESS(GCPhys + cbBuf))
     1392    {
     1393        if (PageAddr != pPageCache->GCPhysReadCacheAddr)
     1394        {
     1395            PDMDevHlpPhysRead(pThis->pDevInsR3, PageAddr,
     1396                              pPageCache->au8PhysReadCache, sizeof(pPageCache->au8PhysReadCache));
     1397            pPageCache->GCPhysReadCacheAddr = PageAddr;
     1398#ifdef VBOX_WITH_OHCI_PHYS_READ_STATS
     1399            ++physReadStats.cPageReads;
     1400#endif
     1401        }
     1402
     1403        memcpy(pvBuf, &pPageCache->au8PhysReadCache[GCPhys & PAGE_OFFSET_MASK], cbBuf);
     1404#ifdef VBOX_WITH_OHCI_PHYS_READ_STATS
     1405        ++physReadStats.cCacheReads;
     1406#endif
     1407    }
     1408    else
     1409    {
     1410        PDMDevHlpPhysRead(pThis->pDevInsR3, GCPhys, pvBuf, cbBuf);
     1411#ifdef VBOX_WITH_OHCI_PHYS_READ_STATS
     1412        ++physReadStats.cCrossReads;
     1413#endif
     1414    }
     1415}
     1416
     1417static void ohciReadEdCached(POHCI pThis, uint32_t EdAddr, POHCIED pEd)
     1418{
     1419    ohciPhysReadCacheRead(pThis, pThis->pCacheED, EdAddr, pEd, sizeof(*pEd));
     1420}
     1421
     1422static void ohciReadTdCached(POHCI pThis, uint32_t TdAddr, POHCITD pTd)
     1423{
     1424    ohciPhysReadCacheRead(pThis, pThis->pCacheTD, TdAddr, pTd, sizeof(*pTd));
     1425}
     1426#endif /* VBOX_WITH_OHCI_PHYS_READ_CACHE */
     1427
    12401428/**
    12411429 * Reads an OHCIED.
     
    12431431DECLINLINE(void) ohciReadEd(POHCI pThis, uint32_t EdAddr, POHCIED pEd)
    12441432{
     1433#ifdef VBOX_WITH_OHCI_PHYS_READ_STATS
     1434    physReadStatsUpdateDesc(&physReadStats.ed, EdAddr);
     1435    physReadStatsUpdateDesc(&physReadStats.all, EdAddr);
     1436#endif
    12451437    ohciGetDWords(pThis, EdAddr, (uint32_t *)pEd, sizeof(*pEd) >> 2);
    12461438}
     
    12511443DECLINLINE(void) ohciReadTd(POHCI pThis, uint32_t TdAddr, POHCITD pTd)
    12521444{
     1445#ifdef VBOX_WITH_OHCI_PHYS_READ_STATS
     1446    physReadStatsUpdateDesc(&physReadStats.td, TdAddr);
     1447    physReadStatsUpdateDesc(&physReadStats.all, TdAddr);
     1448#endif
    12531449    ohciGetDWords(pThis, TdAddr, (uint32_t *)pTd, sizeof(*pTd) >> 2);
    12541450#ifdef LOG_ENABLED
     
    27612957    }   Head;
    27622958
     2959#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     2960    ohciPhysReadCacheClear(pThis->pCacheTD);
     2961#endif
     2962
    27632963    /* read the head */
     2964#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     2965    ohciReadTdCached(pThis, TdAddr, &Head.Td);
     2966#else
    27642967    ohciReadTd(pThis, TdAddr, &Head.Td);
     2968#endif
    27652969    ohciBufInit(&Head.Buf, Head.Td.cbp, Head.Td.be);
    27662970    Head.TdAddr = TdAddr;
     
    27802984        pCur->pNext = NULL;
    27812985        pCur->TdAddr = pTail->Td.NextTD & ED_PTR_MASK;
     2986#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     2987        ohciReadTdCached(pThis, pCur->TdAddr, &pCur->Td);
     2988#else
    27822989        ohciReadTd(pThis, pCur->TdAddr, &pCur->Td);
     2990#endif
    27832991        ohciBufInit(&pCur->Buf, pCur->Td.cbp, pCur->Td.be);
    27842992
     
    32803488    {
    32813489        OHCIED Ed;
     3490#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     3491        ohciReadEdCached(pThis, EdAddr, &Ed);
     3492#else
    32823493        ohciReadEd(pThis, EdAddr, &Ed);
     3494#endif
    32833495        Assert(!(Ed.hwinfo & ED_HWINFO_ISO)); /* the guest is screwing us */
    32843496        if (ohciIsEdReady(&Ed))
     
    33743586    {
    33753587        OHCIED Ed;
     3588#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     3589        ohciReadEdCached(pThis, EdAddr, &Ed);
     3590#else
    33763591        ohciReadEd(pThis, EdAddr, &Ed);
     3592#endif
    33773593        Assert(!(Ed.hwinfo & ED_HWINFO_ISO)); /* the guest is screwing us */
    33783594        if (ohciIsEdPresent(&Ed))
     
    34913707    {
    34923708        OHCIED Ed;
     3709#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     3710        ohciReadEdCached(pThis, EdAddr, &Ed);
     3711#else
    34933712        ohciReadEd(pThis, EdAddr, &Ed);
     3713#endif
    34943714
    34953715        if (ohciIsEdReady(&Ed))
     
    36233843    Assert(cLeft == 0);
    36243844
     3845#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     3846    /* Get hcca data to minimize calls to ohciGetDWords/PDMDevHlpPhysRead. */
     3847    uint32_t au32HCCA[OHCI_HCCA_NUM_INTR];
     3848    ohciGetDWords(pThis, pThis->hcca, au32HCCA, OHCI_HCCA_NUM_INTR);
     3849#endif
     3850
    36253851    /* Go over all bulk/control/interrupt endpoint lists; any URB found in these lists
    36263852     * is marked as active again.
     
    36373863            break;
    36383864        default:
     3865#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     3866            EdAddr = au32HCCA[i];
     3867#else
    36393868            ohciGetDWords(pThis, pThis->hcca + i * sizeof(EdAddr), &EdAddr, 1);
     3869#endif
    36403870            break;
    36413871        }
     
    36443874            OHCIED Ed;
    36453875            OHCITD Td;
     3876#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     3877            ohciReadEdCached(pThis, EdAddr, &Ed);
     3878#else
    36463879            ohciReadEd(pThis, EdAddr, &Ed);
     3880#endif
    36473881            uint32_t TdAddr = Ed.HeadP & ED_PTR_MASK;
    36483882            uint32_t TailP  = Ed.TailP & ED_PTR_MASK;
     
    36513885                && (TdAddr != TailP))
    36523886            {
     3887#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     3888                ohciPhysReadCacheClear(pThis->pCacheTD);
     3889#endif
    36533890                do
    36543891                {
     3892#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     3893                    ohciReadTdCached(pThis, TdAddr, &Td);
     3894#else
    36553895                    ohciReadTd(pThis, TdAddr, &Td);
     3896#endif
    36563897                    j = ohci_in_flight_find(pThis, TdAddr);
    36573898                    if (j > -1)
    36583899                        pThis->aInFlight[j].fInactive = false;
    36593900                    TdAddr = Td.NextTD & ED_PTR_MASK;
     3901                    /* See #8125.
     3902                     * Sometimes the ED is changed by the guest between ohciReadEd above and here.
     3903                     * Then the code reads TD pointed by the new TailP, which is not allowed.
     3904                     * Luckily Windows guests have Td.NextTD = 0 in the tail TD.
     3905                     * Also having a real TD at 0 is very unlikely.
     3906                     * So do not continue.
     3907                     */
     3908                    if (TdAddr == 0)
     3909                        break;
    36603910                    /* Failsafe for temporarily looped lists. */
    36613911                    if (++k == 128)
     
    38114061    pThis->fIdle = true;
    38124062
     4063#ifdef VBOX_WITH_OHCI_PHYS_READ_STATS
     4064    physReadStatsReset(&physReadStats);
     4065#endif
     4066
     4067#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     4068    ohciPhysReadCacheClear(pThis->pCacheED);
     4069    ohciPhysReadCacheClear(pThis->pCacheTD);
     4070#endif
     4071
    38134072    /* Frame boundary, so do EOF stuff here. */
    38144073    bump_frame_number(pThis);
     
    38214080    /* Start the next frame. */
    38224081    ohciStartOfFrame(pThis);
     4082
     4083#ifdef VBOX_WITH_OHCI_PHYS_READ_STATS
     4084    physReadStatsPrint(&physReadStats);
     4085#endif
    38234086
    38244087    RTCritSectLeave(&pThis->CritSect);
     
    55925855    PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
    55935856
     5857#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     5858    ohciPhysReadCacheFree(pThis->pCacheED);
     5859    pThis->pCacheED = NULL;
     5860    ohciPhysReadCacheFree(pThis->pCacheTD);
     5861    pThis->pCacheTD = NULL;
     5862#endif
     5863
    55945864    if (RTCritSectIsInitialized(&pThis->CritSect))
    55955865        RTCritSectDelete(&pThis->CritSect);
     
    57676037        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
    57686038                                   N_("OHCI: Failed to create critical section"));
     6039
     6040#ifdef VBOX_WITH_OHCI_PHYS_READ_CACHE
     6041    pThis->pCacheED = ohciPhysReadCacheAlloc();
     6042    pThis->pCacheTD = ohciPhysReadCacheAlloc();
     6043    if (pThis->pCacheED == NULL || pThis->pCacheTD == NULL)
     6044        return PDMDevHlpVMSetError(pDevIns, VERR_NO_MEMORY, RT_SRC_POS,
     6045                                   N_("OHCI: Failed to allocate PhysRead cache"));
     6046#endif
    57696047
    57706048    /*
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