We know that Java runs in two places where reordering is possible: when the compiler compiles and when the processor is running. So we should ask why reorder with instructions?
Life analogy
Let’s take life as an example. Let’s say you have a box of red paper. Now you have to cut red flowers and paste them on the window. You have two extreme options: take one out, cut it out, and post it on…… One by one; Another way is to take it all out first, then cut it all out, and then paste it all on.
Which is more efficient? The latter is obvious, since the former involves constantly switching between boxes, scissors and glue, a process that wastes both time and energy. But the latter has been doing a job is also very boring, will lead to half a day on the window without a flower, will give you a sense of loss, so the more appropriate approach is to take out a stack, cut this stack, paste up. This is not boring, but also reduces the number of switching, improve work efficiency.
Think again, if there are three people, one to carry, one to cut, and one to paste, it will be faster.
Analysis of the
What are the benefits of compile time reordering? The CPU accesses values when it evaluates, and if it often uses values that are already in the register, it doesn’t need to read them in memory, for example
int a = 1;
int b = 1;
a = a + 1;
b = b +1 ;
Copy the code
There might not be
int a = 1;
a = a + 1;
int b = 1;
b = b +1 ;
Copy the code
The performance is good because the latter can either a or B may be in the register.
Why does the processor reorder? Because a assembly instruction will involve a lot of steps, each step may use different registers, CPU USES the technology of assembly line, that is to say, the CPU has multiple functional units, such as acquisition, decoding, operation, and the results, an instruction is divided into multiple cells, then the first instruction execution haven’t finished, you can perform the next instruction, The premise is that the two instruction function units are the same or similar, so generally, instructions can be rearranged to make the instructions with similar function units executed in succession to reduce the interruption of the pipeline.
Let’s write some code to try it out:
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;
}
}
Copy the code
Running results:
# {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 ; *iaddCopy the code
In other words, mov was used to load the three values needed in the method, and then add was used to perform the addition operation.
Now let’s comment out the //*** line and run it as follows:
[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 ; *iaddCopy the code
The addition operation is still performed after loading all values with mov instruction. To sum up, no matter how later the value is used in the code, it is loaded with MOV first and then calculated with Add.
Note that the above operation parameters for Xcomp – XX: XX + UnlockDiagnosticVMOptions – : CompileCommand = print, * the ReOrder add1 – XX: + PrintCompilation. Xcomp means to use CompileCommand rather than interpret mode. -xx :CompileCommand=print,* reorder. add1 means to print only this method, and -xx :+PrintCompilation means to print the method name. Hsdis plug-in is required, compiled and placed in the JDK’s JRE bin server, the specific environment can be set up here
If the analysis is wrong, please pat. Access to the original