ฉันอ้างว่าเป็นเพื่อนร่วมงานที่if (i < input.size() - 1) print(0);
จะได้รับการเพิ่มประสิทธิภาพในวงนี้เพื่อที่input.size()
จะไม่ได้อ่านทุกครั้ง แต่มันกลับกลายเป็นว่านี่ไม่ใช่กรณี!
void print(int x) {
std::cout << x << std::endl;
}
void print_list(const std::vector<int>& input) {
int i = 0;
for (size_t i = 0; i < input.size(); i++) {
print(input[i]);
if (i < input.size() - 1) print(0);
}
}
ตามCompiler Explorerพร้อมตัวเลือก gcc -O3 -fno-exceptions
เรากำลังอ่านการinput.size()
วนซ้ำแต่ละครั้งและใช้lea
เพื่อทำการลบ!
movq 0(%rbp), %rdx
movq 8(%rbp), %rax
subq %rdx, %rax
sarq $2, %rax
leaq -1(%rax), %rcx
cmpq %rbx, %rcx
ja .L35
addq $1, %rbx
ที่น่าสนใจใน Rust การเพิ่มประสิทธิภาพนี้เกิดขึ้น ดูเหมือนว่าi
จะได้รับการแทนที่ด้วยตัวแปรj
ที่เป็น decremented ซ้ำกันและการทดสอบจะถูกแทนที่ด้วยสิ่งที่ชอบi < input.size() - 1
j > 0
fn print(x: i32) {
println!("{}", x);
}
pub fn print_list(xs: &Vec<i32>) {
for (i, x) in xs.iter().enumerate() {
print(*x);
if i < xs.len() - 1 {
print(0);
}
}
}
ในคอมไพเลอร์ Explorerแอสเซมบลีที่เกี่ยวข้องมีลักษณะดังนี้:
cmpq %r12, %rbx
jae .LBB0_4
ฉันตรวจสอบและฉันค่อนข้างแน่ใจว่าr12
เป็นxs.len() - 1
และrbx
เป็นเคาน์เตอร์ ก่อนหน้านี้มีการadd
สำหรับrbx
และด้านนอกของวงเข้าmov
r12
ทำไมนี้ ดูเหมือนว่าหาก GCC สามารถอินไลน์ได้size()
และoperator[]
อย่างที่มันทำมันควรจะรู้ว่าsize()
มันไม่เปลี่ยนแปลง แต่เครื่องมือเพิ่มประสิทธิภาพของ GCC อาจตัดสินว่ามันไม่คุ้มค่าที่จะดึงมันออกมาเป็นตัวแปรหรือไม่? หรืออาจมีผลข้างเคียงอื่น ๆ ที่อาจทำให้สิ่งนี้ไม่ปลอดภัย - ไม่มีใครรู้หรือไม่?
cout.operator<<()
นี่คือปัญหาการเรียกฟังก์ชั่นที่ไม่ใช่แบบอินไลน์ไป คอมไพเลอร์ไม่ทราบว่าฟังก์ชั่นกล่องดำนี้ไม่ได้รับการอ้างอิงถึงstd::vector
จากโกลบอล
println
หรือoperator<<
เป็นกุญแจ
println
อาจจะเป็นวิธีการที่ซับซ้อนคอมไพเลอร์อาจจะมีปัญหาในการพิสูจน์ว่าprintln
ไม่กลายพันธุ์เวกเตอร์