LTP GCOV extension - code coverage report
Current view: directory - src/libutil - aterm-map.cc
Test: app.info
Date: 2006-10-11 Instrumented lines: 98
Code covered: 84.7 % Executed lines: 83

       1                 : #include "aterm-map.hh"
       2                 : 
       3                 : #include <iostream>
       4                 : 
       5                 : #include <assert.h>
       6                 : #include <stdlib.h>
       7                 : 
       8                 : #include <aterm2.h>
       9                 : 
      10                 : 
      11                 : namespace nix {
      12                 : 
      13                 : 
      14                 : static const unsigned int maxLoadFactor = /* 1 / */ 3;
      15                 : static unsigned int nrResizes = 0;
      16                 : static unsigned int sizeTotalAlloc = 0;
      17                 : static unsigned int sizeCurAlloc = 0;
      18                 : static unsigned int sizeMaxAlloc = 0;
      19                 : 
      20                 : 
      21                 : ATermMap::ATermMap(unsigned int expectedCount)
      22            2310 : {
      23            2310 :     init(expectedCount);
      24                 : }
      25                 : 
      26                 : 
      27                 : ATermMap::ATermMap(const ATermMap & map)
      28             274 : {
      29             274 :     init(map.maxCount);
      30             274 :     copy(map.hashTable, map.capacity);
      31                 : }
      32                 : 
      33                 : 
      34                 : ATermMap & ATermMap::operator = (const ATermMap & map)
      35               0 : {
      36               0 :     if (this == &map) return *this;
      37               0 :     free();
      38               0 :     init(map.maxCount);
      39               0 :     copy(map.hashTable, map.capacity);
      40               0 :     return *this;
      41                 : }
      42                 : 
      43                 : 
      44                 : ATermMap::~ATermMap()
      45            5168 : {
      46            2584 :     free();
      47                 : }
      48                 : 
      49                 : 
      50                 : void ATermMap::init(unsigned int expectedCount)
      51            2584 : {
      52            2584 :     assert(sizeof(ATerm) * 2 == sizeof(KeyValue));
      53            2584 :     capacity = 0;
      54            2584 :     count = 0;
      55            2584 :     maxCount = 0;
      56            2584 :     hashTable = 0;
      57            2584 :     resizeTable(expectedCount);
      58                 : }
      59                 : 
      60                 : 
      61                 : void ATermMap::free()
      62            2584 : {
      63            2584 :     if (hashTable) {
      64            2584 :         ATunprotectArray((ATerm *) hashTable);
      65            2584 :         ::free(hashTable);
      66            2584 :         sizeCurAlloc -= sizeof(KeyValue) * capacity;
      67            2584 :         hashTable = 0;
      68                 :     }
      69                 : }
      70                 : 
      71                 : 
      72                 : static unsigned int roundToPowerOf2(unsigned int x)
      73            2585 : {
      74            2585 :     x--;
      75            2585 :     x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16;
      76            2585 :     x++;
      77            2585 :     return x;
      78                 : }
      79                 : 
      80                 : 
      81                 : void ATermMap::resizeTable(unsigned int expectedCount)
      82            2585 : {
      83            2585 :     if (expectedCount == 0) expectedCount = 1;
      84                 : //     cout << maxCount << " -> " << expectedCount << endl;
      85                 : //     cout << maxCount << " " << size << endl;
      86                 : //     cout << (double) size / maxCount << endl;
      87                 : 
      88            2585 :     unsigned int oldCapacity = capacity;
      89            2585 :     KeyValue * oldHashTable = hashTable;
      90                 : 
      91            2585 :     maxCount = expectedCount;
      92            2585 :     capacity = roundToPowerOf2(maxCount * maxLoadFactor);
      93            2585 :     hashTable = (KeyValue *) calloc(sizeof(KeyValue), capacity);
      94            2585 :     sizeTotalAlloc += sizeof(KeyValue) * capacity;
      95            2585 :     sizeCurAlloc += sizeof(KeyValue) * capacity;
      96            2585 :     if (sizeCurAlloc > sizeMaxAlloc) sizeMaxAlloc = sizeCurAlloc;
      97            2585 :     ATprotectArray((ATerm *) hashTable, capacity * 2);
      98                 :     
      99                 : //     cout << capacity << endl;
     100                 : 
     101                 :     /* Re-hash the elements in the old table. */
     102            2585 :     if (oldCapacity != 0) {
     103               1 :         count = 0;
     104               1 :         copy(oldHashTable, oldCapacity);
     105               1 :         ATunprotectArray((ATerm *) oldHashTable);
     106               1 :         ::free(oldHashTable);
     107               1 :         sizeCurAlloc -= sizeof(KeyValue) * oldCapacity;
     108               1 :         nrResizes++;
     109                 :     }
     110                 : }
     111                 : 
     112                 : 
     113                 : void ATermMap::copy(KeyValue * elements, unsigned int capacity)
     114             275 : {
     115          140571 :     for (unsigned int i = 0; i < capacity; ++i)
     116          140296 :         if (elements[i].value) /* i.e., non-empty, non-deleted element */
     117            9144 :             set(elements[i].key, elements[i].value);
     118                 : }
     119                 : 
     120                 : 
     121                 : /* !!! use a bigger shift for 64-bit platforms? */
     122                 : static const unsigned int shift = 16;
     123                 : static const unsigned long knuth = (unsigned long) (0.6180339887 * (1 << shift));
     124                 : 
     125                 : 
     126                 : unsigned long ATermMap::hash1(ATerm key) const
     127           40761 : {
     128                 :     /* Don't care about the least significant bits of the ATerm
     129                 :        pointer since they're always 0. */
     130           40761 :     unsigned long key2 = ((unsigned long) key) >> 2;
     131                 : 
     132                 :     /* Approximately equal to:
     133                 :     double d = key2 * 0.6180339887;
     134                 :     unsigned int h = (int) (capacity * (d - floor(d)));
     135                 :     */
     136                 :  
     137           40761 :     unsigned long h = (capacity * ((key2 * knuth) & ((1 << shift) - 1))) >> shift;
     138                 : 
     139           40761 :     return h;
     140                 : }
     141                 : 
     142                 : 
     143                 : unsigned long ATermMap::hash2(ATerm key) const
     144             640 : {
     145             640 :     unsigned long key2 = ((unsigned long) key) >> 2;
     146                 :     /* Note: the result must be relatively prime to `capacity' (which
     147                 :        is a power of 2), so we make sure that the result is always
     148                 :        odd. */
     149             640 :     unsigned long h = ((key2 * 134217689) & (capacity - 1)) | 1;
     150             640 :     return h;
     151                 : }
     152                 : 
     153                 : 
     154                 : static unsigned int nrItemsSet = 0;
     155                 : static unsigned int nrSetProbes = 0;
     156                 : 
     157                 : 
     158                 : void ATermMap::set(ATerm key, ATerm value)
     159           28255 : {
     160           28255 :     if (count == maxCount) resizeTable(capacity * 2 / maxLoadFactor);
     161                 :     
     162           28255 :     nrItemsSet++;
     163           28334 :     for (unsigned int i = 0, h = hash1(key); i < capacity;
     164                 :          ++i, h = (h + hash2(key)) & (capacity - 1))
     165                 :     {
     166                 :         // assert(h < capacity);
     167           28334 :         nrSetProbes++;
     168                 :         /* Note: to see whether a slot is free, we check
     169                 :            hashTable[h].value, not hashTable[h].key, since we use
     170                 :            value == 0 to mark deleted slots. */
     171           28334 :         if (hashTable[h].value == 0 || hashTable[h].key == key) {
     172           28255 :             if (hashTable[h].value == 0) count++;
     173           28255 :             hashTable[h].key = key;
     174           28255 :             hashTable[h].value = value;
     175           28255 :             return;
     176                 :         }
     177                 :     }
     178                 :         
     179               0 :     abort();
     180                 : }
     181                 : 
     182                 : 
     183                 : static unsigned int nrItemsGet = 0;
     184                 : static unsigned int nrGetProbes = 0;
     185                 : 
     186                 : 
     187                 : ATerm ATermMap::get(ATerm key) const
     188           12475 : {
     189           12475 :     nrItemsGet++;
     190           13036 :     for (unsigned int i = 0, h = hash1(key); i < capacity;
     191                 :          ++i, h = (h + hash2(key)) & (capacity - 1))
     192                 :     {
     193           13036 :         nrGetProbes++;
     194           13036 :         if (hashTable[h].key == 0) return 0;
     195            6052 :         if (hashTable[h].key == key) return hashTable[h].value;
     196                 :     }
     197               0 :     return 0;
     198                 : }
     199                 : 
     200                 : 
     201                 : void ATermMap::remove(ATerm key)
     202              31 : {
     203              31 :     for (unsigned int i = 0, h = hash1(key); i < capacity;
     204                 :          ++i, h = (h + hash2(key)) & (capacity - 1))
     205                 :     {
     206              31 :         if (hashTable[h].key == 0) return;
     207              31 :         if (hashTable[h].key == key) {
     208              31 :             if (hashTable[h].value != 0) {
     209              31 :                 hashTable[h].value = 0;
     210              31 :                 count--;
     211                 :             }
     212              31 :             return;
     213                 :         }
     214                 :     }
     215                 : }
     216                 : 
     217                 : 
     218                 : unsigned int ATermMap::size()
     219              44 : {
     220              44 :     return count; /* STL nomenclature */
     221                 : }
     222                 : 
     223                 : 
     224                 : void printATermMapStats()
     225               0 : {
     226               0 :     using std::cerr;
     227               0 :     using std::endl;
     228                 :     
     229               0 :     cerr << "RESIZES: " << nrResizes << " "
     230                 :          << sizeTotalAlloc << " "
     231                 :          << sizeCurAlloc << " "
     232                 :          << sizeMaxAlloc << endl;
     233                 :         
     234               0 :     cerr << "SET: "
     235                 :          << nrItemsSet << " "
     236                 :          << nrSetProbes << " "
     237                 :          << (double) nrSetProbes / nrItemsSet << endl;
     238                 : 
     239               0 :     cerr << "GET: "
     240                 :          << nrItemsGet << " "
     241                 :          << nrGetProbes << " "
     242                 :          << (double) nrGetProbes / nrItemsGet << endl;
     243                 : }
     244                 : 
     245                 : 
     246                 : #if 0
     247                 : int main(int argc, char * * argv)
     248                 : {
     249                 :     ATerm bottomOfStack;
     250                 :     ATinit(argc, argv, &bottomOfStack);
     251                 : 
     252                 :     /* Make test terms. */
     253                 :     int nrTestTerms = 100000;
     254                 :     ATerm testTerms[nrTestTerms];
     255                 : 
     256                 :     for (int i = 0; i < nrTestTerms; ++i) {
     257                 :         char name[10];
     258                 :         sprintf(name, "%d", (int) random() % 37);
     259                 : 
     260                 :         int arity = i == 0 ? 0 : (random() % 37);
     261                 :         ATerm kids[arity];
     262                 :         for (int j = 0; j < arity; ++j)
     263                 :             kids[j] = testTerms[random() % i];
     264                 :         
     265                 :         testTerms[i] = (ATerm) ATmakeApplArray(ATmakeAFun(name, arity, ATfalse), kids);
     266                 : //         ATwriteToSharedTextFile(testTerms[i], stdout);
     267                 : //         printf("\n");
     268                 :     }
     269                 : 
     270                 : 
     271                 :     cout << "testing...\n";
     272                 : 
     273                 :     
     274                 :     #define someTerm() (testTerms[(int) random() % nrTestTerms])
     275                 : 
     276                 : 
     277                 :     for (int test = 0; test < 100000; ++test) {
     278                 :         //cerr << test << endl;
     279                 :         unsigned int n = 300;
     280                 :         ATermMap map(300);
     281                 :         ATerm keys[n], values[n];
     282                 :         for (unsigned int i = 0; i < n; ++i) {
     283                 :             keys[i] = someTerm();
     284                 :             values[i] = someTerm();
     285                 :             map.set(keys[i], values[i]);
     286                 :             //cerr << "INSERT: " << keys[i] << " " << values[i] << endl;
     287                 :         }
     288                 : 
     289                 :         unsigned int size = map.size();
     290                 :         assert(size <= n);
     291                 :         values[n - 1] = 0;
     292                 :         map.remove(keys[n - 1]);
     293                 :         assert(map.size() == size - 1);
     294                 : 
     295                 :         unsigned int checksum;
     296                 :         unsigned int count = 0;
     297                 :         for (ATermMap::const_iterator i = map.begin(); i != map.end(); ++i, ++count) {
     298                 :             assert(i->key);
     299                 :             assert(i->value);
     300                 :             checksum += (unsigned int) (*i).key;
     301                 :             checksum += (unsigned int) (*i).value;
     302                 :             // cout << (*i).key << " " << (*i).value << endl;
     303                 :         }
     304                 :         assert(count == size - 1);
     305                 : 
     306                 :         for (unsigned int i = 0; i < n; ++i) {
     307                 :             for (unsigned int j = i + 1; j < n; ++j)
     308                 :                 if (keys[i] == keys[j]) goto x;
     309                 :             if (map.get(keys[i]) != values[i]) {
     310                 :                 cerr << "MISMATCH: " << keys[i] << " " << values[i] << " " << map.get(keys[i]) << " " << i << endl;
     311                 :                 abort();
     312                 :             }
     313                 :             if (values[i] != 0) {
     314                 :                 checksum -= (unsigned int) keys[i];
     315                 :                 checksum -= (unsigned int) values[i];
     316                 :             }
     317                 :         x:  ;
     318                 :         }
     319                 : 
     320                 :         assert(checksum == 0);
     321                 :         
     322                 :         for (unsigned int i = 0; i < 100; ++i)
     323                 :             map.get(someTerm());
     324                 :         
     325                 :     }
     326                 : 
     327                 :     printATermMapStats();
     328                 : }
     329                 : #endif
     330                 : 
     331                 :  
     332             121 : }

Generated by: LTP GCOV extension version 1.1