Bir RTOS için irq_lock()/irq_unlock() uygulamasında çalışıyorum ve bir sorun bulundu. CPU'nun kesilen kilitlerle ne kadar zaman harcadığını kesinlikle en aza indirmek istiyoruz.GCC'ye sadece yükleme/depolama değil, herhangi bir talimatı yeniden sipariş etmemesini söylemenin bir yolu var mı?
static ALWAYS_INLINE unsigned int _do_irq_lock(void)
{
unsigned int key;
__asm__ volatile (
"pushfl;\n\t"
"cli;\n\t"
"popl %0;\n\t"
: "=g" (key)
:
: "memory"
);
return key;
}
sorun onlar sadece kayıtlarını ve bellek dokunursan derleyici hala kritik bölüme potansiyel pahalı operasyonlar yeniden düzenlemek olacaktır: Şu anda, x86 bizim irq_lock() satır içi işlevi "bellek" clobber kullanır. Spesifik bir örnek bizim çekirdeğin uyku işlevinde buradadır:
void k_sleep(int32_t duration)
{
__ASSERT(!_is_in_isr(), "");
__ASSERT(duration != K_FOREVER, "");
K_DEBUG("thread %p for %d ns\n", _current, duration);
/* wait of 0 ns is treated as a 'yield' */
if (duration == 0) {
k_yield();
return;
}
int32_t ticks = _TICK_ALIGN + _ms_to_ticks(duration);
int key = irq_lock();
_remove_thread_from_ready_q(_current);
_add_thread_timeout(_current, NULL, ticks);
_Swap(key);
}
pahalı matematik yapar 'Keneler' hesaplama, biz kesmeleri kilitlemek içinde nerede yeniden sıralanmış alır, bu yüzden kesintilerini __divdi3 aradığınız değil olan kilitli ne istediğimizi:
Dump of assembler code for function k_sleep:
0x0010197a <+0>: push %ebp
0x0010197b <+1>: mov %esp,%ebp
0x0010197d <+3>: push %ebx
0x0010197e <+4>: push %edx
0x0010197f <+5>: mov 0x8(%ebp),%edx
0x00101982 <+8>: test %edx,%edx
0x00101984 <+10>: jne 0x10198d <k_sleep+19>
0x00101986 <+12>: call 0x101944 <k_yield>
0x0010198b <+17>: jmp 0x1019f5 <k_sleep+123>
0x0010198d <+19>: mov $0x64,%eax
0x00101992 <+24>: push $0x0
0x00101994 <+26>: imul %edx
0x00101996 <+28>: add $0x3e7,%eax
0x0010199b <+33>: push $0x3e8
0x001019a0 <+38>: adc $0x0,%edx
0x001019a3 <+41>: push %edx
0x001019a4 <+42>: push %eax
0x001019a5 <+43>: call 0x1000a0 <__divdi3>
0x001019aa <+48>: add $0x10,%esp
0x001019ad <+51>: inc %eax
0x001019ae <+52>: mov %eax,-0x8(%ebp)
0x001019b1 <+55>: pushf
0x001019b2 <+56>: cli
0x001019b3 <+57>: pop %ebx
0x001019b4 <+58>: pushl 0x1045e8
0x001019ba <+64>: call 0x101726 <_remove_thread_from_ready_q>
0x001019bf <+69>: mov 0x1045e8,%eax
0x001019c4 <+74>: mov -0x8(%ebp),%edx
0x001019c7 <+77>: movl $0x0,0x24(%eax)
0x001019ce <+84>: mov %edx,0x28(%eax)
0x001019d1 <+87>: mov %eax,0x20(%eax)
0x001019d4 <+90>: lea 0x18(%eax),%edx
0x001019d7 <+93>: add $0x28,%eax
0x001019da <+96>: mov %eax,(%esp)
0x001019dd <+99>: mov $0x10162b,%ecx
0x001019e2 <+104>: mov $0x1045ec,%eax
0x001019e7 <+109>: call 0x101667 <sys_dlist_insert_at>
0x001019ec <+114>: mov %ebx,(%esp)
0x001019ef <+117>: call 0x100f77 <_Swap>
0x001019f4 <+122>: pop %eax
0x001019f5 <+123>: mov -0x4(%ebp),%ebx
0x001019f8 <+126>: leave
0x001019f9 <+127>: ret
End of assembler dump.
:
Dump of assembler code for function k_sleep:
0x0010197a <+0>: push %ebp
0x0010197b <+1>: mov %esp,%ebp
0x0010197d <+3>: push %edi
0x0010197e <+4>: push %esi
0x0010197f <+5>: push %ebx
0x00101980 <+6>: mov 0x8(%ebp),%edi
0x00101983 <+9>: test %edi,%edi
0x00101985 <+11>: jne 0x101993 <k_sleep+25>
0x00101987 <+13>: lea -0xc(%ebp),%esp
0x0010198a <+16>: pop %ebx
0x0010198b <+17>: pop %esi
0x0010198c <+18>: pop %edi
0x0010198d <+19>: pop %ebp
0x0010198e <+20>: jmp 0x101944 <k_yield>
0x00101993 <+25>: pushf
0x00101994 <+26>: cli
0x00101995 <+27>: pop %esi
0x00101996 <+28>: pushl 0x104608
0x0010199c <+34>: call 0x101726 <_remove_thread_from_ready_q>
0x001019a1 <+39>: mov $0x64,%eax
0x001019a6 <+44>: imul %edi
0x001019a8 <+46>: mov 0x104608,%ebx
0x001019ae <+52>: add $0x3e7,%eax
0x001019b3 <+57>: adc $0x0,%edx
0x001019b6 <+60>: mov %ebx,0x20(%ebx)
0x001019b9 <+63>: movl $0x0,(%esp)
0x001019c0 <+70>: push $0x3e8
0x001019c5 <+75>: push %edx
0x001019c6 <+76>: push %eax
0x001019c7 <+77>: call 0x1000a0 <__divdi3>
0x001019cc <+82>: add $0x10,%esp
0x001019cf <+85>: inc %eax
0x001019d0 <+86>: mov %eax,0x28(%ebx)
0x001019d3 <+89>: movl $0x0,0x24(%ebx)
0x001019da <+96>: lea 0x18(%ebx),%edx
0x001019dd <+99>: mov $0x10460c,%eax
0x001019e2 <+104>: add $0x28,%ebx
0x001019e5 <+107>: mov $0x10162b,%ecx
0x001019ea <+112>: push %ebx
0x001019eb <+113>: call 0x101667 <sys_dlist_insert_at>
0x001019f0 <+118>: mov %esi,0x8(%ebp)
0x001019f3 <+121>: pop %eax
0x001019f4 <+122>: lea -0xc(%ebp),%esp
0x001019f7 <+125>: pop %ebx
0x001019f8 <+126>: pop %esi
0x001019f9 <+127>: pop %edi
0x001019fa <+128>: pop %ebp
0x001019fb <+129>: jmp 0x100f77 <_Swap>
End of assembler dump.
Biz 'kene' uçucu bildirerek istediğimiz sipariş alabilirsiniz keşfetti 0
Ancak, bu sadece bir noktada giderir. Irq_lock() uygulamasının her yerde doğru şeyi yapacağı şekilde değiştirmesi için bir yönteme ihtiyacımız var ve şu anda "hafıza" yongası yeterli değil.
'stdatomic.h' dosyasına bakın ve bir derleyici bariyeri kullanın. Ayrıca irq-enable/disable'ın gcc'de tipik olarak makro olmasının bir nedeni vardır. – Olaf
Belki de optimizasyon devre dışı bırakılıyor: '-O0'. –
@FiddlingBits: Kötü tavsiye. Kod, optimizasyonun değişmeyeceği şekilde yazılmalıdır. Tamamen devre dışı bırakma optimizasyonu, bir miktar ceza ekleyecektir. – Olaf