ฉันทำโปรไฟล์ด้วยการตั้งค่าต่อไปนี้: เครื่องทดสอบ (AMD Athlon64 x2 3800+) ถูกบูตเปลี่ยนเป็นโหมดยาว (ปิดใช้งานการขัดจังหวะ) และคำสั่งที่น่าสนใจจะดำเนินการแบบวนซ้ำ 100 ครั้งยกเลิกการควบคุมและ 1,000 รอบลูป เนื้อหาของลูปถูกจัดแนวเป็น 16 ไบต์ เวลาถูกวัดด้วยคำสั่ง rdtsc ก่อนและหลังลูป นอกจากนี้ยังมีการดำเนินการลูปจำลองโดยไม่มีคำสั่งใด ๆ (ซึ่งวัดได้ 2 รอบต่อการวนซ้ำและ 14 รอบสำหรับส่วนที่เหลือ) และผลลัพธ์จะถูกลบออกจากผลลัพธ์ของเวลาการทำโปรไฟล์คำสั่ง
คำแนะนำต่อไปนี้วัดได้:
- "
lock cmpxchg [rsp - 8], rdx
" (ทั้งที่มีการจับคู่เปรียบเทียบและไม่ตรงกัน)
- "
lock xadd [rsp - 8], rdx
",
- "
lock bts qword ptr [rsp - 8], 1
"
ในทุกกรณีเวลาที่วัดได้ประมาณ 310 รอบข้อผิดพลาดอยู่ที่ประมาณ +/- 8 รอบ
นี่คือค่าสำหรับการดำเนินการซ้ำบนหน่วยความจำ (แคช) เดียวกัน ด้วยการพลาดแคชเพิ่มเติมเวลาจะสูงขึ้นมาก นอกจากนี้ยังทำได้โดยมีเพียงหนึ่งใน 2 คอร์ที่ใช้งานอยู่ดังนั้นแคชจึงเป็นของเจ้าของโดยเฉพาะและไม่จำเป็นต้องซิงค์แคช
ในการประเมินค่าใช้จ่ายของคำสั่งที่ถูกล็อกในแคชพลาดฉันได้เพิ่มwbinvld
คำสั่งก่อนคำสั่งที่ถูกล็อกและใส่เครื่องหมายwbinvld
บวกadd [rsp - 8], rax
ลงในลูปการเปรียบเทียบ ในทั้งสองกรณีค่าใช้จ่ายประมาณ 80,000 รอบต่อคู่คำสั่ง! ในกรณีที่ล็อค bts เวลาต่างกันประมาณ 180 รอบต่อคำสั่ง
โปรดทราบว่านี่คือทรูพุตซึ่งกันและกัน แต่เนื่องจากการดำเนินการที่ล็อกเป็นการดำเนินการแบบอนุกรมจึงอาจไม่มีความแตกต่างกับเวลาในการตอบสนอง
สรุป: การทำงานที่ล็อคนั้นหนัก แต่การพลาดแคชอาจหนักกว่ามาก นอกจากนี้: การดำเนินการที่ถูกล็อกจะไม่ทำให้แคชพลาด สามารถทำให้เกิดการซิงโครไนซ์แคชได้เฉพาะเมื่อแคชไลน์ไม่ได้เป็นเจ้าของโดยเฉพาะ
ในการบูตเครื่องฉันใช้ FreeLdr เวอร์ชัน x64 จากโครงการ ReactOS นี่คือซอร์สโค้ด asm:
#define LOOP_COUNT 1000
#define UNROLLED_COUNT 100
PUBLIC ProfileDummy
ProfileDummy:
cli
// Get current TSC value into r8
rdtsc
mov r8, rdx
shl r8, 32
or r8, rax
mov rcx, LOOP_COUNT
jmp looper1
.align 16
looper1:
REPEAT UNROLLED_COUNT
// nothing, or add something to compare against
ENDR
dec rcx
jnz looper1
// Put new TSC minus old TSC into rax
rdtsc
shl rdx, 32
or rax, rdx
sub rax, r8
ret
PUBLIC ProfileFunction
ProfileFunction:
cli
rdtsc
mov r8, rdx
shl r8, 32
or r8, rax
mov rcx, LOOP_COUNT
jmp looper2
.align 16
looper2:
REPEAT UNROLLED_COUNT
// Put here the code you want to profile
// make sure it doesn't mess up non-volatiles or r8
lock bts qword ptr [rsp - 8], 1
ENDR
dec rcx
jnz looper2
rdtsc
shl rdx, 32
or rax, rdx
sub rax, r8
ret