Jump to content
Sign in to follow this  
fredericopissarra

Medindo ciclos de clock também no ARM

Recommended Posts

Posted (edited)

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"
Edited by fredericopissarra

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...