Использование стека с внутренними компонентами MMX и Microsoft C ++

Если вам нужна истинная Singleton для загрузчиков классов, вам нужен общий родитель для загрузки рассматриваемого класса или вам нужно указать загрузчик классов самостоятельно.

Обновление: из комментария от @ Pshemo ниже справедливой части содержимого в блоге ниже может появиться непосредственно из статьи JavaWorld . Я оставил запись в блоге, так как он все равно может помочь кому-то, но стоит знать, откуда изначально вышло.

Оригинал: есть запись blog , которая дает вам способ сделать это »(хотя я и не пробовал это!), и он выглядит довольно разумно

. В соответствии с нижеприведенным здесь фрагментом кода из моей ссылки выше - я предлагаю вам посетить блог, хотя для полного context:

private static Class getClass(String classname) throws ClassNotFoundException {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    if(classLoader == null) 
        classLoader = Singleton.class.getClassLoader();
      return (classLoader.loadClass(classname));
}

1
задан starblue 24 May 2010 в 15:08
поделиться

1 ответ

VS2010 выполняет достойную работу по оптимизации эквивалентного кода с использованием встроенных функций. В большинстве случаев он компилирует внутреннее:

sum = _mm_add_pi32(sum, *(__m64 *) &intArray[i + offset]);

в нечто вроде:

movq  mm0, mmword ptr [eax+8*offset]
paddd mm1, mm0

Это не так лаконично, как ваш padd mm1, [esi + edx + 8 * offset] , но, возможно, приходит почти. Время выполнения, вероятно, зависит от выборки из памяти.

Загвоздка в том, что VS, похоже, любит добавлять регистры MMX только к другим регистрам MMX. Приведенная выше схема работает только для первых 7 сумм. 8-я сумма требует временного сохранения некоторого регистра в памяти.

Вот полная программа и соответствующая ей скомпилированная сборка (релизная сборка):

#include <stdio.h>
#include <stdlib.h>
#include <xmmintrin.h>

void addWithInterleavedIntrinsics(int *interleaved, int count)
{
    // sum up the numbers
    __m64 sum0 = _mm_setzero_si64(), sum1 = _mm_setzero_si64(),
          sum2 = _mm_setzero_si64(), sum3 = _mm_setzero_si64(),
          sum4 = _mm_setzero_si64(), sum5 = _mm_setzero_si64(),
          sum6 = _mm_setzero_si64(), sum7 = _mm_setzero_si64();

    for (int i = 0; i < 16 * count; i += 16) {
        sum0 = _mm_add_pi32(sum0, *(__m64 *) &interleaved[i]);
        sum1 = _mm_add_pi32(sum1, *(__m64 *) &interleaved[i + 2]);
        sum2 = _mm_add_pi32(sum2, *(__m64 *) &interleaved[i + 4]);
        sum3 = _mm_add_pi32(sum3, *(__m64 *) &interleaved[i + 6]);
        sum4 = _mm_add_pi32(sum4, *(__m64 *) &interleaved[i + 8]);
        sum5 = _mm_add_pi32(sum5, *(__m64 *) &interleaved[i + 10]);
        sum6 = _mm_add_pi32(sum6, *(__m64 *) &interleaved[i + 12]);
        sum7 = _mm_add_pi32(sum7, *(__m64 *) &interleaved[i + 14]);
    }

    // reset the MMX/floating-point state
    _mm_empty();

    // write out the sums; we have to do something with the sums so that
    // the optimizer doesn't just decide to avoid computing them.
    printf("%.8x %.8x\n", ((int *) &sum0)[0], ((int *) &sum0)[1]);
    printf("%.8x %.8x\n", ((int *) &sum1)[0], ((int *) &sum1)[1]);
    printf("%.8x %.8x\n", ((int *) &sum2)[0], ((int *) &sum2)[1]);
    printf("%.8x %.8x\n", ((int *) &sum3)[0], ((int *) &sum3)[1]);
    printf("%.8x %.8x\n", ((int *) &sum4)[0], ((int *) &sum4)[1]);
    printf("%.8x %.8x\n", ((int *) &sum5)[0], ((int *) &sum5)[1]);
    printf("%.8x %.8x\n", ((int *) &sum6)[0], ((int *) &sum6)[1]);
    printf("%.8x %.8x\n", ((int *) &sum7)[0], ((int *) &sum7)[1]);
}

void main()
{
    int count        = 10000;
    int *interleaved = new int[16 * count];

    // create some random numbers to add up
    // (note that on VS2010, RAND_MAX is just 32767)
    for (int i = 0; i < 16 * count; ++i) {
        interleaved[i] = rand();
    }

    addWithInterleavedIntrinsics(interleaved, count);
}

Вот сгенерированный ассемблерный код для внутренней части цикла суммы (без его пролога и эпилога). Обратите внимание, как эффективно ведется большая часть сумм в мм1-мм6. Сравните это с mm0, которое используется для прибавления числа к каждой сумме, и с mm7, которое служит последним двум суммам.Версия этой программы с 7 суммами, похоже, не имеет проблемы с mm7.

012D1070  movq        mm7,mmword ptr [esp+18h]  
012D1075  movq        mm0,mmword ptr [eax-10h]  
012D1079  paddd       mm1,mm0  
012D107C  movq        mm0,mmword ptr [eax-8]  
012D1080  paddd       mm2,mm0  
012D1083  movq        mm0,mmword ptr [eax]  
012D1086  paddd       mm3,mm0  
012D1089  movq        mm0,mmword ptr [eax+8]  
012D108D  paddd       mm4,mm0  
012D1090  movq        mm0,mmword ptr [eax+10h]  
012D1094  paddd       mm5,mm0  
012D1097  movq        mm0,mmword ptr [eax+18h]  
012D109B  paddd       mm6,mm0  
012D109E  movq        mm0,mmword ptr [eax+20h]  
012D10A2  paddd       mm7,mm0  
012D10A5  movq        mmword ptr [esp+18h],mm7  
012D10AA  movq        mm0,mmword ptr [esp+10h]  
012D10AF  movq        mm7,mmword ptr [eax+28h]  
012D10B3  add         eax,40h  
012D10B6  dec         ecx  
012D10B7  paddd       mm0,mm7  
012D10BA  movq        mmword ptr [esp+10h],mm0  
012D10BF  jne         main+70h (12D1070h)  

Итак, что вы можете сделать?

  1. Профилируйте программы, основанные на 7 и 8 суммах. Выберите тот, который выполняется быстрее.

  2. Профилируйте версию, которая добавляет только один регистр MMX за раз. Он по-прежнему должен иметь возможность использовать тот факт, что современные процессоры извлекают от 64 до 128 байтов в кэш за раз . Не очевидно, что версия с 8 суммой будет быстрее, чем версия с 1 суммой. Версия с 1 суммой извлекает точно такой же объем памяти и выполняет такое же количество добавлений MMX. Однако вам нужно будет соответствующим образом чередовать входы.

  3. Если ваше целевое оборудование позволяет это, рассмотрите возможность использования инструкций SSE . Они могут добавлять 4 32-битных значения за раз. SSE доступен в процессорах Intel начиная с Pentium III в 1999 году.

2
ответ дан 3 September 2019 в 00:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: