This page describes how to find out what features a CPU supports. There are two different use cases for needing this information. The first is casual probing via the command line. The other is when making decisions at runtime in your source code.

Generic Approaches To Feature Determination

$ cat /proc/cpuinfo | grep "^Features"
Features        : swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls

You can also do it programmatically. The code below dumps the value of AT_HWCAP. You can decode this value using asm/hwcap.h

/**
 * This program is derived from information in:
 *    http://articles.manugarg.com/aboutelfauxiliaryvectors.html
 */
#include <stdio.h>
#include <elf.h>

int main(int argc, char *argv[], char *envp[])
{
        Elf32_auxv_t *auxv;
        while(*envp++ != NULL); /*auxv follows envp*/

        auxv = (Elf32_auxv_t*)envp;
        while (auxv && auxv->a_type != AT_HWCAP)
                auxv++;

        if (auxv)
                printf("hwcaps: %u\n", auxv->a_un.a_val);
        return 0;
}

Determining Neon Support

$ cat /proc/cpuinfo | grep "^Features.*neon"
Features        : swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls3

This can also be done in code with something like:

/**
 * This program is derived from information in:
 *    http://articles.manugarg.com/aboutelfauxiliaryvectors.html
 */
#include <stdio.h>
#include <elf.h>
#include <asm/hwcap.h>

int main(int argc, char *argv[], char *envp[])
{
        Elf32_auxv_t *auxv;
        while(*envp++ != NULL); /*auxv follows envp*/

        auxv = (Elf32_auxv_t*)envp;
        while (auxv && auxv->a_type != AT_HWCAP)
                auxv++;

        if( auxv && auxv->a_un.a_val & HWCAP_NEON )
                printf("NEON capable!\n");
        return 0;
}

Determining Neon Support In A Library

The approach from a library is a little different as the auxv must be obtained via a different method. In these examples ElfW is used which is 32/64 bit independent.

volatile ElfW(auxv_t) *auxv = NULL;

LOCAL(ElfW(auxv_t) *)get_auxv(void)
{
  FILE *auxv_f;
  ElfW(auxv_t) auxv_struct;
  int i = 0;

  if(auxv == NULL) {
    auxv_f = fopen("/proc/self/auxv", "r");

    if(auxv_f == 0) {
       perror("Error opening file for reading");
          return 0;
    }
    auxv =(ElfW(auxv_t) *)malloc(getpagesize());

    do
      {
      fread(&auxv_struct, sizeof(ElfW(auxv_t)), 1, auxv_f);
      auxv[i] = auxv_struct;
      i++;
      } while(auxv_struct.a_type != AT_NULL);
  }
  return auxv;
}

With the auxv in hand one can use code like the following to determine if HWCAP_NEON is present and set in this case a global simd_support variable.

void
init_simd (void)
{
  char *env=NULL;
  ElfW(auxv_t) *tauxv=(ElfW(auxv_t) *)auxv;

  while (tauxv && tauxv->a_type != AT_HWCAP)
    tauxv++;

  if( tauxv && tauxv->a_un.a_val & HWCAP_NEON )
    simd_support = 1;

}


CategoryHowTo

Resources/HowTo/DeterminingCPUFeatures (last modified 2011-09-29 23:22:48)