Если вам нужна истинная 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));
}
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)
Итак, что вы можете сделать?
Профилируйте программы, основанные на 7 и 8 суммах. Выберите тот, который выполняется быстрее.
Профилируйте версию, которая добавляет только один регистр MMX за раз. Он по-прежнему должен иметь возможность использовать тот факт, что современные процессоры извлекают от 64 до 128 байтов в кэш за раз . Не очевидно, что версия с 8 суммой будет быстрее, чем версия с 1 суммой. Версия с 1 суммой извлекает точно такой же объем памяти и выполняет такое же количество добавлений MMX. Однако вам нужно будет соответствующим образом чередовать входы.
Если ваше целевое оборудование позволяет это, рассмотрите возможность использования инструкций SSE . Они могут добавлять 4 32-битных значения за раз. SSE доступен в процессорах Intel начиная с Pentium III в 1999 году.