fredericopissarra Posted May 6, 2019 Posted May 6, 2019 Costumo usar essas "funçõeszinhas" para medir a quantidade de ciclos de clock "gastos" por uma função. Acrescentei o suporte ao AArch64. O AArch32 também tem, mas é mais complicado. Note que o PMC (Performance Monitoring Counter) usado no AArch64 é para o privilégio 0 (user). PS: Esse troço funciona bem com processadores das famílias Ivy Bridge em diante. Não sei quanto aos anteriores... E, no caso do ARM, para o Cortex A-52 em diante é certo... #ifndef CYCLE_COUNTING_INCLUDED__ #define CYCLE_COUNTING_INCLUDED__ #ifndef __GNUC__ # error Works only on GCC #endif /* ========================================== Quick & Dirty cycle counting... As funções usadas para contar a quantidade de ciclos de clock gastos num bloco de código. Exemplo de uso: uint64_t t; BEGIN_TSC(); f(); t = END_TSC(); É conveniente compilar o código sob teste com a opção -O0, já que o compilador poderá 'sumir' com o código, por causa da otimização. Para i386 e x86-64 defina SYNC_MEM se quiser uma serialização mais completa. ========================================== */ #include <stdint.h> uint64_t $local_tsc__; #if defined(__x86_64__) inline void BEGIN_TSC( void ) { uint32_t a, d; __asm__ __volatile__ ( # ifdef SYNC_MEM "mfence\n\t" # endif "xorl %%eax,%%eax\n\t" "cpuid\n\t" "rdtsc" : "=a" (a), "=d" (d) :: "%rbx", "%rcx" ); $local_tsc__ = a + (uint64_t)d << 32; } inline uint64_t END_TSC( void ) { uint32_t a, d; __asm__ __volatile__ ( "rdtscp" : "=a" (a), "=d" (d) :: "%rcx" ); return (a + (uint64_t)d << 32) - $local_tsc__; } #elif defined(__i386__) inline void BEGIN_TSC( void ) { uint32_t a, d; __asm__ __volatile__ ( # ifdef SYNC_MEM "mfence\n\t" # endif "xorl %%eax,%%eax\n\t" "cpuid\n\t" "rdtsc" : "=a" (a), "=d" (d) :: "%ebx", "%ecx" ); $local_tsc__ = a + (uint64_t)d << 32; } inline uint64_t END_TSC( void ) { uint32_t a, d; __asm__ __volatile__ ( "rdtscp" : "=a" (a), "=d" (d) :: "%ecx" ); return (a + (uint64_t)d << 32) - $local_tsc__; } #elif defined(__aarch64__) inline void BEGIN_TSC( void ) { uint64_t count; __asm__ __volatile__ ( "mrs %0,cntvct_el0" : "=r" (count) ); $local_tsc__ = count; } inline uint64_t END_TSC( void ) { uint64_t count; __asm__ __volatile__ ( "mrs %0,cntvct_el0" : "=r" (count) ); return count - $local_tsc__; } #else # error i386, x86-64 and AArch64 only. #endif #endif Se quiser que BEGIN_TSC() espere por todas as leituras e escritas pendentes (para diminuir os efeitos do cache L1), defina o símbolo SYNC_MEM antes de incluir esse header, como em: #define SYNC_MEM #include "cycle_counting.h"
Recommended Posts
Archived
This topic is now archived and is closed to further replies.