void run(ureg threadIndex) {
     u32 x = X;
     u32 y = Y;
     while ((g_random[threadIndex].next32() & 0x7f) != 0) { // Random delay
     }
     switch (threadIndex) {
     case 0:
         // We store 2 because Junction maps reserve 1 for the default Redirect value.
         // The default can be overridden, but this is easier.
         m_map.assign(x, (void*) 2);
         break;
         
     case 1:
         m_map.assign(y, (void*) 2);
         break;
         
     case 2:
         m_r1 = (uptr) m_map.get(x);
         m_r2 = (uptr) m_map.get(y);
         break;
         
     case 3:
         m_r3 = (uptr) m_map.get(y);
         m_r4 = (uptr) m_map.get(x);
         break;
     }
 }
 void initialPopulate() {
     TURF_ASSERT(m_addIndex == m_removeIndex);
     MapAdapter::Map *map = m_shared.map;
     for (ureg i = 0; i < m_shared.numKeysPerThread; i++) {
         u32 key = m_addIndex * Prime;
         map->insert(key, (void*) (key & ~uptr(3)));
         if (++m_addIndex == m_rangeHi)
             m_addIndex = m_rangeLo;
     }
 }
    void run() {
        MapAdapter::Map *map = m_shared.map;
        turf::CPUTimer::Converter converter;
        Delay delay(m_shared.delayFactor);
        Stats stats;
        ureg lookupIndex = m_rangeLo;
        ureg remaining = m_shared.itersPerChunk;
        if (m_threadIndex == 0)
            m_shared.spinKicker.kick(m_shared.numThreads - 1);
        else {
            remaining = ~u32(0);
            m_shared.spinKicker.waitForKick();
        }

        // ---------
        turf::CPUTimer::Point start = turf::CPUTimer::get();
        for (; remaining > 0; remaining--) {
            // Add
            delay.delay(stats.workUnitsDone);
            if (m_shared.doneFlag.load(turf::Relaxed))
                break;
            u32 key = m_addIndex * Prime;
            if (key >= 2) {
                map->insert(key, (void*) uptr(key));
                stats.mapOpsDone++;
            }
            if (++m_addIndex == m_rangeHi)
                m_addIndex = m_rangeLo;

            // Lookup
            if (s32(lookupIndex - m_removeIndex) < 0)
                lookupIndex = m_removeIndex;
            for (ureg l = 0; l < m_shared.readsPerWrite; l++) {
                delay.delay(stats.workUnitsDone);
                if (m_shared.doneFlag.load(turf::Relaxed))
                    break;
                key = lookupIndex * Prime;
                if (key >= 2) {
                    volatile void* value = map->get(key);
                    TURF_UNUSED(value);
                    stats.mapOpsDone++;
                }
                if (++lookupIndex == m_rangeHi)
                    lookupIndex = m_rangeLo;
                if (lookupIndex == m_addIndex)
                    lookupIndex = m_removeIndex;
            }

            // Remove
            delay.delay(stats.workUnitsDone);
            if (m_shared.doneFlag.load(turf::Relaxed))
                break;
            key = m_removeIndex * Prime;
            if (key >= 2) {
                map->erase(key);
                stats.mapOpsDone++;
            }
            if (++m_removeIndex == m_rangeHi)
                m_removeIndex = m_rangeLo;

            // Lookup
            if (s32(lookupIndex - m_removeIndex) < 0)
                lookupIndex = m_removeIndex;
            for (ureg l = 0; l < m_shared.readsPerWrite; l++) {
                delay.delay(stats.workUnitsDone);
                if (m_shared.doneFlag.load(turf::Relaxed))
                    break;
                key = lookupIndex * Prime;
                if (key >= 2) {
                    volatile void* value = map->get(key);
                    TURF_UNUSED(value);
                    stats.mapOpsDone++;
                }
                if (++lookupIndex == m_rangeHi)
                    lookupIndex = m_rangeLo;
                if (lookupIndex == m_addIndex)
                    lookupIndex = m_removeIndex;
            }
        }
        if (m_threadIndex == 0)
            m_shared.doneFlag.store(1, turf::Relaxed);
        m_threadCtx.update();
        turf::CPUTimer::Point end = turf::CPUTimer::get();
        // ---------

        stats.duration = converter.toSeconds(end - start);
        m_stats = stats;
    }