VirtualBox

Changeset 1017 in kBuild


Ignore:
Timestamp:
Jun 3, 2007 2:49:52 AM (18 years ago)
Author:
bird
Message:

Implemented an usable method for comparing files and avoiding changes in blank spaces (#defines and stuff). It has a tiny deficiency on VCC dependencies, but we can live with that.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kObjCache/kObjCache.c

    r1016 r1017  
    3838#include <fcntl.h>
    3939#include <limits.h>
     40#include <ctype.h>
    4041#ifndef PATH_MAX
    4142# define PATH_MAX _MAX_PATH /* windows */
     
    385386                        unsigned char ch = pszMD5[i];
    386387                        int x;
    387                         if (ch - '0' <= 9)
     388                        if ((unsigned char)(ch - '0') <= 9)
    388389                            x = ch - '0';
    389                         else if (ch - 'a' <= 5)
     390                        else if ((unsigned char)(ch - 'a') <= 5)
    390391                            x = ch - 'a' + 10;
    391                         else if (ch - 'A' <= 5)
     392                        else if ((unsigned char)(ch - 'A') <= 5)
    392393                            x = ch - 'A' + 10;
    393394                        else
     
    668669    for (;;)
    669670    {
    670         long cbRead = read(fds[0], psz, cbLeft);
     671        long cbRead = read(fds[0], psz, cbLeft - 1);
    671672        if (!cbRead)
    672673            break;
     
    674675            kObjCacheFatal(pEntry, "%s - read(%d,,%ld) failed: %s\n", pszMsg, fds[0], (long)cbLeft, strerror(errno));
    675676        psz += cbRead;
     677        *psz = '\0';
    676678        cbLeft -= cbRead;
    677679
    678680        /* expand the buffer? */
    679         if (!cbLeft)
     681        if (cbLeft <= 1)
    680682        {
    681683            size_t off = psz - *ppszOutput;
     
    826828
    827829/**
    828  * Worker for kObjCacheCompileIfNeeded that compares the
    829  * precompiled output.
     830 * Check whether the string is a '#line' statement.
     831 *
     832 * @returns 1 if it is, 0 if it isn't.
     833 * @param   psz         The line to examin.
     834 * @parma   piLine      Where to store the line number.
     835 * @parma   ppszFile    Where to store the start of the filename.
     836 */
     837static int IsLineStatement(const char *psz, unsigned *piLine, const char **ppszFile)
     838{
     839    unsigned iLine;
     840
     841    /* Expect a hash. */
     842    if (*psz++ != '#')
     843        return 0;
     844
     845    /* Skip blanks between '#' and the line / number */
     846    while (*psz == ' ' || *psz == '\t')
     847        psz++;
     848
     849    /* Skip the 'line' if present. */
     850    if (!strncmp(psz, "line", sizeof("line") - 1))
     851        psz += sizeof("line");
     852
     853    /* Expect a line number now. */
     854    if ((unsigned char)(*psz - '0') > 9)
     855        return 0;
     856    iLine = 0;
     857    do 
     858    {
     859        iLine *= 10;
     860        iLine += (*psz - '0');
     861        psz++;
     862    }
     863    while ((unsigned char)(*psz - '0') <= 9);
     864
     865    /* Expect one or more space now. */
     866    if (*psz != ' ' && *psz != '\t')
     867        return 0;
     868    do  psz++;
     869    while (*psz == ' ' || *psz == '\t');
     870
     871    /* that's good enough. */
     872    *piLine = iLine;
     873    *ppszFile = psz;
     874    return 1;
     875}
     876
     877
     878/**
     879 * Scan backwards for the previous #line statement.
     880 *
     881 * @returns The filename in the previous statement.
     882 * @param   pszStart        Where to start.
     883 * @param   pszStop         Where to stop. Less than pszStart.
     884 * @param   piLine          The line number count to adjust.
     885 */
     886static const char *FindFileStatement(const char *pszStart, const char *pszStop, unsigned *piLine)
     887{
     888    unsigned iLine = *piLine;
     889    assert(pszStart >= pszStop);
     890    while (pszStart >= pszStop)
     891    {
     892        if (*pszStart == '\n')
     893            iLine++;
     894        else if (*pszStart == '#')
     895        {
     896            unsigned iLineTmp;
     897            const char *pszFile;
     898            const char *psz = pszStart - 1;
     899            while (psz >= pszStop && (*psz == ' ' || *psz =='\t'))
     900                psz--;
     901            if (    (psz < pszStop || *psz == '\n')
     902                &&  IsLineStatement(pszStart, &iLineTmp, &pszFile))
     903            {
     904                *piLine = iLine + iLineTmp - 1;
     905                return pszFile;
     906            }
     907        }
     908        pszStart--;
     909    }
     910    return NULL;
     911}
     912
     913
     914/**
     915 * Worker for kObjCacheCompareOldAndNewOutput() that compares the
     916 * precompiled output using a fast but not very good method.
    830917 *
    831918 * @returns 1 if matching, 0 if not matching.
     
    833920 *                      The entry is not updated in any way.
    834921 */
    835 static int kObjCacheCompareOldAndNewOutput(PCKOBJCACHE pEntry)
     922static int kObjCacheCompareFast(PCKOBJCACHE pEntry)
     923{
     924    const char *        psz1 = pEntry->pszNewCppMapping;
     925    const char * const  pszEnd1 = psz1 + pEntry->cbNewCpp;
     926    const char *        psz2 = pEntry->pszOldCppMapping;
     927    const char * const  pszEnd2 = psz2 + pEntry->cbOldCpp;
     928
     929    assert(*pszEnd1 == '\0');
     930    assert(*pszEnd2 == '\0');
     931
     932    /*
     933     * Iterate block by block and backtrack when we find a difference.
     934     */
     935    for (;;)
     936    {
     937        size_t cch = pszEnd1 - psz1;
     938        if (cch > (size_t)(pszEnd2 - psz2))
     939            cch = pszEnd2 - psz2;
     940        if (cch > 4096)
     941            cch = 4096;
     942        if (    cch
     943            &&  !memcmp(psz1, psz2, cch))
     944        {
     945            /* no differences */
     946            psz1 += cch;
     947            psz2 += cch;
     948        }
     949        else
     950        {
     951            /*
     952             * Pinpoint the difference exactly and the try find the start
     953             * of that line. Then skip forward until we find something to
     954             * work on that isn't spaces or #line statements. Since we
     955             * might be skipping a few new empty headers, it is possible
     956             * that we will omit this header from the dependencies when
     957             * using VCC. But I think that's a reasonable trade off for
     958             * a simple algorithm.
     959             */
     960            const char *psz;
     961            const char *pszMismatch1;
     962            const char *pszFile1 = NULL;
     963            unsigned    iLine1 = 0;
     964            const char *pszMismatch2;
     965            const char *pszFile2 = NULL;
     966            unsigned    iLine2 = 0;
     967
     968            /* locate the difference. */
     969            while (cch >= 512 && !memcmp(psz1, psz2, 512))
     970                psz1 += 512, psz2 += 512, cch -= 512;
     971            while (cch >= 64 && !memcmp(psz1, psz2, 64))
     972                psz1 += 64, psz2 += 64, cch -= 64;
     973            while (*psz1 == *psz2 && cch > 0)
     974                psz1++, psz2++, cch--;
     975
     976            /* locate the start of that line. */
     977            psz = psz1;
     978            while (     psz > pEntry->pszNewCppMapping
     979                   &&   psz[-1] != '\n')
     980                psz--;
     981            psz2 -= (psz1 - psz);
     982            pszMismatch2 = psz2;
     983            pszMismatch1 = psz1 = psz;
     984
     985            /* Parse the 1st file line by line. */
     986            while (psz1 < pszEnd1)
     987            {
     988                if (*psz1 == '\n')
     989                {
     990                    psz1++;
     991                    iLine1++;
     992                }
     993                else
     994                {
     995                    psz = psz1;
     996                    while (isspace(*psz) && *psz != '\n')
     997                        psz++;
     998                    if (*psz == '\n')
     999                    {
     1000                        psz1 = psz + 1;
     1001                        iLine1++;
     1002                    }
     1003                    else if (*psz == '#' && IsLineStatement(psz, &iLine1, &pszFile1))
     1004                    {
     1005                        psz1 = memchr(psz, '\n', pszEnd1 - psz);
     1006                        if (!psz1++)
     1007                            psz1 = pszEnd1;
     1008                    }
     1009                    else if (psz == pszEnd1)
     1010                        psz1 = psz;
     1011                    else /* found something that can be compared. */
     1012                        break;
     1013                }
     1014            }
     1015
     1016            /* Ditto for the 2nd file. */
     1017            while (psz2 < pszEnd2)
     1018            {
     1019                if (*psz2 == '\n')
     1020                {
     1021                    psz2++;
     1022                    iLine2++;
     1023                }
     1024                else
     1025                {
     1026                    psz = psz2;
     1027                    while (isspace(*psz) && *psz != '\n')
     1028                        psz++;
     1029                    if (*psz == '\n')
     1030                    {
     1031                        psz2 = psz + 1;
     1032                        iLine2++;
     1033                    }
     1034                    else if (*psz == '#' && IsLineStatement(psz, &iLine2, &pszFile2))
     1035                    {
     1036                        psz2 = memchr(psz, '\n', pszEnd2 - psz);
     1037                        if (!psz2++)
     1038                            psz2 = pszEnd2;
     1039                    }
     1040                    else if (psz == pszEnd2)
     1041                        psz2 = psz;
     1042                    else /* found something that can be compared. */
     1043                        break;
     1044                }
     1045            }
     1046
     1047            /* Reaching the end of any of them means the return statement can decide. */
     1048            if (   psz1 == pszEnd1
     1049                || psz2 == pszEnd2)
     1050                break;
     1051
     1052            /* Match the current line. */
     1053            psz = memchr(psz1, '\n', pszEnd1 - psz1);
     1054            if (!psz)
     1055                psz = pszEnd1;
     1056            cch = psz - psz1;
     1057            if (psz2 + cch > pszEnd2)
     1058                break;
     1059            if (memcmp(psz1, psz2, cch))
     1060                break;
     1061
     1062            /* Check that we're at the same location now. */
     1063            if (!pszFile1)
     1064                pszFile1 = FindFileStatement(pszMismatch1, pEntry->pszNewCppMapping, &iLine1);
     1065            if (!pszFile2)
     1066                pszFile2 = FindFileStatement(pszMismatch2, pEntry->pszOldCppMapping, &iLine2);
     1067            if (pszFile1 && pszFile2)
     1068            {
     1069                if (iLine1 != iLine2)
     1070                    break;
     1071                while (*pszFile1 == *pszFile2 && *pszFile1 != '\n' && *pszFile1)
     1072                    pszFile1++, pszFile2++;
     1073                if (*pszFile1 != *pszFile2)
     1074                    break;
     1075            }
     1076            else if (pszFile1 || pszFile2)
     1077            {
     1078                assert(0); /* this shouldn't happen. */
     1079                break;
     1080            }
     1081
     1082            /* Try align psz1 on 8 or 4 bytes so at least one of the buffers are aligned. */
     1083            psz1 += cch;
     1084            psz2 += cch;
     1085            if (cch >= ((uintptr_t)psz1 & 7))
     1086            {
     1087                psz2 -= ((uintptr_t)psz1 & 7);
     1088                psz1 -= ((uintptr_t)psz1 & 7);
     1089            }
     1090            else if (cch >= ((uintptr_t)psz1 & 3))
     1091            {
     1092                psz2 -= ((uintptr_t)psz1 & 3);
     1093                psz1 -= ((uintptr_t)psz1 & 3);
     1094            }
     1095        }
     1096    }
     1097
     1098    return psz1 == pszEnd1
     1099        && psz2 == pszEnd2;
     1100}
     1101
     1102
     1103/**
     1104 * Worker for kObjCacheCompileIfNeeded that compares the
     1105 * precompiled output.
     1106 *
     1107 * @returns 1 if matching, 0 if not matching.
     1108 * @param   pEntry      The entry containing the names of the files to compare.
     1109 *                      This will load the old cpp output (changing pszOldCppName and cbOldCpp).
     1110 */
     1111static int kObjCacheCompareOldAndNewOutput(PKOBJCACHE pEntry)
    8361112{
    8371113    /** @todo do some quick but fancy comparing that determins whether code
     
    8391115     * has just been moved up/down a bit. The typical case is adding a new error
    8401116     * #define that doesn't influence the current compile job. */
    841     return 0;
     1117
     1118    /*
     1119     * Load the old output.
     1120     */
     1121    pEntry->pszOldCppMapping = ReadFileInDir(pEntry->pszOldCppName, pEntry->pszDir, &pEntry->cbOldCpp);
     1122    if (!pEntry->pszOldCppMapping)
     1123    {
     1124        kObjCacheVerbose(pEntry, "failed to read old cpp file ('%s' in '%s'): %s\n",
     1125                         pEntry->pszOldCppName, pEntry->pszDir, strerror(errno));
     1126        return 0;
     1127    }
     1128
     1129    /*
     1130     * I may implement a more sophisticated alternative method later... maybe.
     1131     */
     1132    //if ()
     1133    //    return kObjCacheCompareBest(pEntry);
     1134    return kObjCacheCompareFast(pEntry);
    8421135}
    8431136
     
    9831276
    9841277    /*
    985      * Discard the old precompiled output it's no longer needed.s
    986      */
    987     if (pEntry->pszOldCppName)
     1278     * Discard the old precompiled output if it's no longer needed.
     1279     */
     1280    if (    pEntry->pszOldCppName
     1281        &&  (   !pEntry->fPiped
     1282             || pEntry->fNeedCompiling))
    9881283    {
    9891284        UnlinkFileInDir(pEntry->pszOldCppName, pEntry->pszDir);
     
    14421737     */
    14431738    kObjCacheWrite(pEntry);
    1444     //kObjCacheCleanup(pEntry);
    14451739    /* kObjCacheDestroy(pEntry); - don't bother */
    14461740    return 0;
    14471741}
    14481742
     1743
     1744/** @page kObjCache Benchmarks.
     1745 *
     1746 * 2007-06-02 - 21-23:00:
     1747 * Mac OS X debug -j 3 clobber build (rm -Rf out/darwin.x86/debug ; sync ; svn diff ; sync ; sleep 1 ; time kmk -j 3):
     1748 *  real    10m26.077s
     1749 *  user    13m13.291s
     1750 *  sys     2m58.193s
     1751 *
     1752 * Mac OS X debug -j 3 depend build (touch include/iprt/err.h ; sync ; svn diff ; sync ; sleep 1 ; time kmk -j 3):
     1753 *  real    3m55.275s                                                                                           
     1754 *  user    4m11.852s
     1755 *  sys     0m54.931s
     1756 *
     1757 * Mac OS X debug -j 3 cached clobber build (rm -Rf out/darwin.x86/debug ; sync ; svn diff ; sync ; sleep 1 ; time kmk -j 3 USE_KOBJCACHE=1):
     1758 *  real    11m42.513s
     1759 *  user    14m27.736s
     1760 *  sys     3m39.512s
     1761 *
     1762 * Mac OS X debug -j 3 cached clobber build (touch include/iprt/err.h ; sync ; svn diff ; sync ; sleep 1 ; time kmk -j 3 USE_KOBJCACHE=1):
     1763 *  real    2m24.712s       real    2m10.909s 
     1764 *  user    2m15.339s       user    2m15.146s 
     1765 *  sys     0m56.278s       sys     0m55.591s 
     1766 *  !Stuff is built three times here because of + instead of +| in footer.kmk!
     1767 *
     1768 */
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