Зачем переупорядочивать инструкции?

Java задняя часть переводчик

Мы знаем, что переупорядочивание может использоваться в двух местах во время работы Java: одно — при компиляции компилятора, а другое — во время работы процессора. Тогда мы должны спросить, зачем использовать переупорядочение инструкций?

аналогия с жизнью

Возьмем пример из жизни Допустим, у вас есть коробка из красной бумаги, и теперь вы хотите вырезать маленькие красные цветочки и приклеить их на окно. У вас есть два крайних варианта: взять один, вырезать это и вставить... один за другим; другой способ - сначала взять все, затем вырезать все и вставить все в конце.

Что эффективнее? Очевидно последнее, потому что с первым вам нужно постоянно переключаться между коробками, ножницами и клеем, что является пустой тратой времени и энергии. Но последнее тоже очень скучно постоянно заниматься делом, а также приведет к длительному времени без цветка на окне, что принесет вам чувство утраты, поэтому целесообразнее вынести стопку , вырежьте этот стек и вставьте его. Это не скучно, но также снижает количество переключений и повышает эффективность работы.

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

анализировать

Каковы преимущества переупорядочения во время компиляции? Когда ЦП вычисляет, ему необходимо получить доступ к значению.Если часто используется существующее значение в регистре, нет необходимости читать его из памяти.Например,

int a = 1;
int b = 1;
a = a + 1;
b = b +1 ;

А может и не быть

int a = 1;
a = a + 1;
int b = 1;
b = b +1 ;

Хорошая производительность, так как последний может либо a, либо b уже быть в регистре.

Почему процессоры должны быть переупорядочены? Поскольку инструкция сборки также включает много шагов, каждый шаг может использовать разные регистры, ЦП использует конвейерную технологию, то есть ЦП имеет несколько функциональных блоков (таких как выборка, декодирование, операция и результат), Инструкции также делятся на несколько единицы, поэтому вторая инструкция может быть выполнена до завершения выполнения первой инструкции.Предпосылка состоит в том, что функциональные единицы двух инструкций одинаковы или похожи.Поэтому, как правило, можно изменить порядок инструкций, чтобы они имели схожие Инструкции выполняются одна за другой, чтобы уменьшить количество прерываний конвейера.

Давайте напишем кусок кода, чтобы попробовать:

package *****;

/**
 * reorder
 * @author Mageek Chiu
 * @date 2018/5/25 0025:12:49
 */
public class ReOrder {

    public int value ;

    private ReOrder(int value) {
        this.value = value;
    }

    public static void main(String... args){
        ReOrder reOrder = new ReOrder(111);
        ReOrder reOrder1 = new ReOrder(222);
        ReOrder reOrder2 = new ReOrder(333);
        System.out.println(add1(reOrder,reOrder1,reOrder2));
    }

    static int add1(ReOrder reOrder,ReOrder reOrder1,ReOrder reOrder2){
        int result = 0;

        result += reOrder.value;
        result += reOrder1.value;
        result += reOrder2.value;//***

        result += reOrder.value;
        result += reOrder1.value;
        result += reOrder2.value;

        result += reOrder.value;
        result += reOrder1.value;
        result += reOrder2.value;

        return result;

    }

}

В рабочем результате:

 # {method} {0x000000001c402c80} 'add1' '(*****/ReOrder;*****/ReOrder;*****/ReOrder;)I' in '*****/ReOrder'
  # parm0:    rdx:rdx   = '*****/ReOrder'
  # parm1:    r8:r8     = '*****/ReOrder'
  # parm2:    r9:r9     = '*****/ReOrder'
  #           [sp+0x20]  (sp of caller)
  0x00000000032a86c0: mov     dword ptr [rsp+0ffffffffffffa000h],eax
  0x00000000032a86c7: push    rbp
  0x00000000032a86c8: sub     rsp,10h           ;*synchronization entry
                                                ; - *****.ReOrder::add1@-1 (line 24)

  0x00000000032a86cc: mov     r11d,dword ptr [rdx+0ch]
                                                ;*getfield value
                                                ; - *****.ReOrder::add1@4 (line 26)
                                                ; implicit exception: dispatches to 0x00000000032a86ff
  0x00000000032a86d0: mov     r10d,dword ptr [r8+0ch]  ;*getfield value
                                                ; - *****.ReOrder::add1@11 (line 27)
                                                ; implicit exception: dispatches to 0x00000000032a870d
  0x00000000032a86d4: mov     r9d,dword ptr [r9+0ch]  ;*getfield value
                                                ; - *****.ReOrder::add1@18 (line 28)
                                                ; implicit exception: dispatches to 0x00000000032a8719
  0x00000000032a86d8: mov     eax,r11d
  0x00000000032a86db: add     eax,r10d
  0x00000000032a86de: add     eax,r9d
  0x00000000032a86e1: add     eax,r11d
  0x00000000032a86e4: add     eax,r10d
  0x00000000032a86e7: add     eax,r9d
  0x00000000032a86ea: add     eax,r11d
  0x00000000032a86ed: add     eax,r10d
  0x00000000032a86f0: add     eax,r9d           ;*iadd

То есть использовать сначалаmovПоместите три требуемых в методvalueзагружен, а затем использовать его равномерноaddВыполните операцию сложения.

Теперь мы ставим//***Какая строка закомментирована, текущий результат выглядит следующим образом:

[Constants]
  # {method} {0x000000001c052c78} 'add1' '(*****/ReOrder;*****/ReOrder;*****/ReOrder;)I' in '*****/ReOrder'
  # parm0:    rdx:rdx   = '*****/ReOrder'
  # parm1:    r8:r8     = '*****/ReOrder'
  # parm2:    r9:r9     = '*****/ReOrder'
  #           [sp+0x20]  (sp of caller)
  0x0000000002f47d40: mov     dword ptr [rsp+0ffffffffffffa000h],eax
  0x0000000002f47d47: push    rbp
  0x0000000002f47d48: sub     rsp,10h           ;*synchronization entry
                                                ; - *****.ReOrder::add1@-1 (line 24)

  0x0000000002f47d4c: mov     r11d,dword ptr [rdx+0ch]
                                                ;*getfield value
                                                ; - *****r.ReOrder::add1@4 (line 26)
                                                ; implicit exception: dispatches to 0x0000000002f47d7c
  0x0000000002f47d50: mov     r10d,dword ptr [r8+0ch]  ;*getfield value
                                                ; - *****.ReOrder::add1@11 (line 27)
                                                ; implicit exception: dispatches to 0x0000000002f47d89
  0x0000000002f47d54: mov     r9d,dword ptr [r9+0ch]  ;*getfield value
                                                ; - *****::add1@32 (line 32)
                                                ; implicit exception: dispatches to 0x0000000002f47d95
  0x0000000002f47d58: mov     eax,r11d
  0x0000000002f47d5b: add     eax,r10d
  0x0000000002f47d5e: add     eax,r11d
  0x0000000002f47d61: add     eax,r10d
  0x0000000002f47d64: add     eax,r9d
  0x0000000002f47d67: add     eax,r11d
  0x0000000002f47d6a: add     eax,r10d
  0x0000000002f47d6d: add     eax,r9d           ;*iadd

все равно поставить всеvalueиспользовать обаmovОперация сложения выполняется после загрузки инструкции. Подводя итог, неважно, как позже значение будет использовано в коде, используйте его первым.movиспользовать после загрузкиaddРаботайте с этим значением.

Обратите внимание, что приведенные выше параметры запуска-Xcomp -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=print,*ReOrder.add1 -XX:+PrintCompilation.XcompСмысл в том, чтобы использовать скомпилированный режим вместо интерпретируемого,-XX:CompileCommand=print,*ReOrder.add1Указывает, что печатается только этот метод,-XX:+PrintCompilationУказывает имя метода печати. требуется плагинhsdis, поставить после компиляцииjdk的jre的bin的serverХорошо быть посередине.здесь

Пожалуйста, нажмите, если анализ неверен. доступоригинальный