Java - оптимизировать функцию, которая содержит в основном простые математические

1

Я должен попытаться оптимизировать этот метод для своей команды, работая над видеодекодером на Java, хотя я не вижу никакого хорошего подхода к этому. Функция, приведенная ниже, не кажется, что она может ускоряться в любом значительном количестве, поскольку она содержит в основном простое сложение/вычитание/и т.д.

void inverseTransform(int macroBlockIndex, int dataBlockIndex) {
    int[] workSpace = new int[64];
    short[] data = new short[64];

    int z1, z2, z3, z4, z5;
    int tmp0, tmp1, tmp2, tmp3;
    int tmp10, tmp11, tmp12, tmp13;

    int pointer = 0;

    for (int index = 8; index > 0; index--) {
        if (dataBlockBuffer[pointer + 8] == 0 && dataBlockBuffer[pointer + 16] == 0 && dataBlockBuffer[pointer + 24] == 0 && dataBlockBuffer[pointer + 32] == 0 && dataBlockBuffer[pointer + 40] == 0 && dataBlockBuffer[pointer + 48] == 0 && dataBlockBuffer[pointer + 56] == 0) {
            int dcValue = dataBlockBuffer[pointer] << PASS1_BITS;

            workSpace[pointer + 0] = dcValue;
            workSpace[pointer + 8] = dcValue;
            workSpace[pointer + 16] = dcValue;
            workSpace[pointer + 24] = dcValue;
            workSpace[pointer + 32] = dcValue;
            workSpace[pointer + 40] = dcValue;
            workSpace[pointer + 48] = dcValue;
            workSpace[pointer + 56] = dcValue;

            pointer++;
            continue;
        }

        z2 = dataBlockBuffer[pointer + 16];
        z3 = dataBlockBuffer[pointer + 48];

        z1 = (z2 + z3) * FIX_0_541196100;
        tmp2 = z1 + z3 * -FIX_1_847759065;
        tmp3 = z1 + z2 * FIX_0_765366865;

        z2 = dataBlockBuffer[pointer];
        z3 = dataBlockBuffer[pointer + 32];

        tmp0 = (z2 + z3) << BITS;
        tmp1 = (z2 - z3) << BITS;

        tmp10 = tmp0 + tmp3;
        tmp13 = tmp0 - tmp3;
        tmp11 = tmp1 + tmp2;
        tmp12 = tmp1 - tmp2;

        tmp0 = dataBlockBuffer[pointer + 56];
        tmp1 = dataBlockBuffer[pointer + 40];
        tmp2 = dataBlockBuffer[pointer + 24];
        tmp3 = dataBlockBuffer[pointer + 8];

        z1 = tmp0 + tmp3;
        z2 = tmp1 + tmp2;
        z3 = tmp0 + tmp2;
        z4 = tmp1 + tmp3;
        z5 = (z3 + z4) * FIX_1_175875602;

        tmp0 = tmp0 * FIX_0_298631336;
        tmp1 = tmp1 * FIX_2_053119869;
        tmp2 = tmp2 * FIX_3_072711026;
        tmp3 = tmp3 * FIX_1_501321110;
        z1 = z1 * -FIX_0_899976223;
        z2 = z2 * -FIX_2_562915447;
        z3 = z3 * -FIX_1_961570560;
        z4 = z4 * -FIX_0_390180644;

        z3 += z5;
        z4 += z5;

        tmp0 += z1 + z3;
        tmp1 += z2 + z4;
        tmp2 += z2 + z3;
        tmp3 += z1 + z4;

        workSpace[pointer + 0] = ((tmp10 + tmp3 + (1 << F1)) >> F2);
        workSpace[pointer + 56] = ((tmp10 - tmp3 + (1 << F1)) >> F2);
        workSpace[pointer + 8] = ((tmp11 + tmp2 + (1 << F1)) >> F2);
        workSpace[pointer + 48] = ((tmp11 - tmp2 + (1 << F1)) >> F2);
        workSpace[pointer + 16] = ((tmp12 + tmp1 + (1 << F1)) >> F2);
        workSpace[pointer + 40] = ((tmp12 - tmp1 + (1 << F1)) >> F2);
        workSpace[pointer + 24] = ((tmp13 + tmp0 + (1 << F1)) >> F2);
        workSpace[pointer + 32] = ((tmp13 - tmp0 + (1 << F1)) >> F2);

        pointer++;
    }

    pointer = 0;

    for (int index = 0; index < 8; index++) {
        z2 = workSpace[pointer + 2];
        z3 = workSpace[pointer + 6];

        z1 = (z2 + z3) * FIX_0_541196100;
        tmp2 = z1 + z3 * -FIX_1_847759065;
        tmp3 = z1 + z2 * FIX_0_765366865;

        tmp0 = (workSpace[pointer + 0] + workSpace[pointer + 4]) << BITS;
        tmp1 = (workSpace[pointer + 0] - workSpace[pointer + 4]) << BITS;

        tmp10 = tmp0 + tmp3;
        tmp13 = tmp0 - tmp3;
        tmp11 = tmp1 + tmp2;
        tmp12 = tmp1 - tmp2;

        tmp0 = workSpace[pointer + 7];
        tmp1 = workSpace[pointer + 5];
        tmp2 = workSpace[pointer + 3];
        tmp3 = workSpace[pointer + 1];

        z1 = tmp0 + tmp3;
        z2 = tmp1 + tmp2;
        z3 = tmp0 + tmp2;
        z4 = tmp1 + tmp3;

        z5 = (z3 + z4) * FIX_1_175875602;

        tmp0 = tmp0 * FIX_0_298631336;
        tmp1 = tmp1 * FIX_2_053119869;
        tmp2 = tmp2 * FIX_3_072711026;
        tmp3 = tmp3 * FIX_1_501321110;
        z1 = z1 * -FIX_0_899976223;
        z2 = z2 * -FIX_2_562915447;
        z3 = z3 * -FIX_1_961570560;
        z4 = z4 * -FIX_0_390180644;

        z3 += z5;
        z4 += z5;

        tmp0 += z1 + z3;
        tmp1 += z2 + z4;
        tmp2 += z2 + z3;
        tmp3 += z1 + z4;

        data[pointer + 0] = (short) ((tmp10 + tmp3) >> F3);
        data[pointer + 7] = (short) ((tmp10 - tmp3) >> F3);
        data[pointer + 1] = (short) ((tmp11 + tmp2) >> F3);
        data[pointer + 6] = (short) ((tmp11 - tmp2) >> F3);
        data[pointer + 2] = (short) ((tmp12 + tmp1) >> F3);
        data[pointer + 5] = (short) ((tmp12 - tmp1) >> F3);
        data[pointer + 3] = (short) ((tmp13 + tmp0) >> F3);
        data[pointer + 4] = (short) ((tmp13 - tmp0) >> F3);

        pointer += 8;
    }
    short[] temp = imageSlice.MacroBlocks[macroBlockIndex].DataBlocks[dataBlockIndex];
    for (int i = 0; i < data.length; i++)
        temp[i] = data[i]; //imageSlice.MacroBlocks[macroBlockIndex].DataBlocks[dataBlockIndex][i] = data[i];
}

Должен ли я объединить базовую математику, если смогу, или что бы вы предложили?

  • 1
    Большинство из них предложит: найти, где снижение производительности, создать меньшую проблему для отображения и снова задать вопрос с этой информацией
  • 0
    Что ж, два цикла for занимают примерно одинаковое количество времени, поэтому производительность метода в целом снижается. Я мог бы разделить дисплей на каждый отдельный цикл for, но тогда это было бы в двух отдельных постах.
Показать ещё 3 комментария
Теги:
optimization
mathematical-optimization

3 ответа

1
Лучший ответ

Я не вижу ничего очевидного. В дополнение к тому, что сказал Алекс, есть два небольших предложения, которые могут помочь:

1) Оператор long if в первом цикле имеет ряд условий отказа. Вы заказали его так, чтобы сперва было сбой? С оценкой короткого замыкания, чем раньше вы можете найти false тем меньше работы нужно сделать для оценки всего выражения.

2) Вы объявляете множество переменных за пределами двух циклов for-loops, и я могу понять, почему вы это сделали. Возможно, что JVM будет более способна оптимизировать ситуацию, если вы перемещаете объявления внутри двух циклов, чтобы переменные объявлялись как можно локальнее.

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

У меня есть еще один комментарий. В строках типа:

data[pointer + 7] = (short) ((tmp10 - tmp3) >> F3);

вы используете >> вместо >>> для битвыдвижения, возможно, отрицательного числа. Вы уверены, что это то, что вы хотите сделать, если tmp3> tmp10?

  • 0
    Спасибо за совет. Я буду смотреть больше на это.
1

Как и другие плакаты, я думаю, что вы можете сделать это очень мало, чтобы оптимизировать это как таковое.

Я просто попытаюсь прочесть все значения (dataBlockBuffer [x]) в локальные переменные перед состоянием, а затем изменить ваше условие на:

if ((data0 | data1 | data2 |...) == 0)...

Таким образом, у вас потенциально меньше ветвей и где условие терпит неудачу (предположительно большую часть времени?), Данные уже готовы к локальным переменным.

Но это говорит, я не думаю, что вы сильно побритесь.

Еще одна очень незначительная вещь, которую следует учитывать, заключается в том, что упаковка ByteBuffer вокруг массива позволяет вам потенциально читать/записывать сразу несколько значений, если вы можете увидеть способ сделать это. (По крайней мере, когда вы пишете "dcValue" несколько раз, вы можете написать длинный вместо этого, если компилятор JIT не сделает эту оптимизацию).

На рабочем столе я мог бы подумать:

  • многопоточность для обработки нескольких блоков одновременно (большинство людей имеют по крайней мере два ядра в наши дни, но возможно, возможно, не на Android);
  • глядя на JIT-компилируемый вывод и убедившись, что компилятор JIT не делает ничего откровенно глупого, а затем перерабатывает код соответственно (вы можете сделать это с помощью отладки JDK, но не знаете, есть ли эквивалент для Android);
  • возможность nativising, а затем использование GPU/любых разумных прагм, которые ваш компилятор C, возможно, придется скомпилировать для конкретных инструкций SSE/эквивалента (я не эксперт в этом и не знаю, насколько это возможно в вашем случае),

Я бы рассмотрел последние два как "экстремальные" варианты anyway-- с риском инвестирования значительного времени для небольшого выигрыша.

1

Без конкретных доказательств проблем с производительностью я могу увидеть пару возможных улучшений (хотя не знаю, какое улучшение вы получите от них).

  1. Заменить повторяющиеся вычисления на переменные. Например, pointer+7 повторяется несколько раз. Вы можете рассчитать его один раз.
  2. Используйте System.arraycopy() для копирования массива в конце.
  • 0
    Вычисление указателя + 7 только один раз не ускорит код до такой степени, чтобы иметь большое значение, но спасибо за System.arraycopy ().
  • 0
    Какие доказательства вам нужны? Первый цикл for занимает примерно 730 миллионов наносекунд, а второй цикл for - около 790 миллионов, при этом dataBlockBuffer устанавливается в виде массива размером 64, причем для каждого пятна задано значение «1».
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню