text: /*
   * Copyright 2008  Veselin Georgiev,
   * anrieffNOSPAM @ mgail_DOT.com (convert to gmail)
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in the
   *    documentation and/or other materials provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  #ifndef __LIBCPUID_H__
  #define __LIBCPUID_H__
  /**
   * @File     libcpuid.h
   * @Author   Veselin Georgiev
   * @Date     Oct 2008
   * @Version  0.2.1
   *
   * Version history:
   *
   *  0.1.0 (2008-10-15): initial adaptation from wxfractgui sources
   *  0.1.1 (2009-07-06): Added intel_fn11 fields to cpu_raw_data_t to handle
   *                      new processor topology enumeration required on Core i7
   *  0.1.2 (2009-09-26): Added support for MSR reading through self-extracting
   *                      kernel driver on Win32.
   *  0.1.3 (2010-04-20): Added support for greater more accurate CPU clock
   *                      measurements with cpu_clock_by_ic()
   *  0.2.0 (2011-10-11): Support for AMD Bulldozer CPUs, 128-bit SSE unit size
   *                      checking. A backwards-incompatible change, since the
   *                      sizeof cpu_id_t is now different.
   *  0.2.1 (2012-05-26): Support for Ivy Bridge, and detecting the presence of
   *                      the RdRand instruction.
   */
  
  /** @mainpage A simple libcpuid introduction
   *
   * LibCPUID provides CPU identification and access to the CPUID and RDTSC
   * instructions on the x86.
   * <p>
   * To execute CPUID, use \ref cpu_exec_cpuid <br>
   * To execute RDTSC, use \ref cpu_rdtsc <br>
   * To fetch the CPUID info needed for CPU identification, use
   *   \ref cpuid_get_raw_data <br>
   * To make sense of that data (decode, extract features), use \ref cpu_identify <br>
   * </p>
   */
  
  /** @defgroup libcpuid LibCPUID
   @{ */
  
  /* Include some integer type specifications: */
  #include "libcpuid_types.h"
  
  /* Some limits and other constants */
  #include "libcpuid_constants.h"
  
  #ifdef __cplusplus
  extern "C" {
  #endif
  
  /**
   * @brief CPU vendor, as guessed from the Vendor String.
   */
  typedef enum {
  	VENDOR_INTEL = 0,  /*!< Intel CPU */
  	VENDOR_AMD,        /*!< AMD CPU */
  	VENDOR_CYRIX,      /*!< Cyrix CPU */
  	VENDOR_NEXGEN,     /*!< NexGen CPU */
  	VENDOR_TRANSMETA,  /*!< Transmeta CPU */
  	VENDOR_UMC,        /*!< x86 CPU by UMC */
  	VENDOR_CENTAUR,    /*!< x86 CPU by IDT */
  	VENDOR_RISE,       /*!< x86 CPU by Rise Technology */
  	VENDOR_SIS,        /*!< x86 CPU by SiS */
  	VENDOR_NSC,        /*!< x86 CPU by National Semiconductor */
  	
  	NUM_CPU_VENDORS,   /*!< Valid CPU vendor ids: 0..NUM_CPU_VENDORS - 1 */
  	VENDOR_UNKNOWN = -1,
  } cpu_vendor_t;
  #define NUM_CPU_VENDORS NUM_CPU_VENDORS
  
  /**
   * @brief Contains just the raw CPUID data.
   *
   * This contains only the most basic CPU data, required to do identification
   * and feature recognition. Every processor should be identifiable using this
   * data only.
   */
  struct cpu_raw_data_t {
  	/** contains results of CPUID for eax = 0, 1, ...*/
  	uint32_t basic_cpuid[MAX_CPUID_LEVEL][4];
  
  	/** contains results of CPUID for eax = 0x80000000, 0x80000001, ...*/
  	uint32_t ext_cpuid[MAX_EXT_CPUID_LEVEL][4];
  	
  	/** when the CPU is intel and it supports deterministic cache
  	    information: this contains the results of CPUID for eax = 4
  	    and ecx = 0, 1, ... */
  	uint32_t intel_fn4[MAX_INTELFN4_LEVEL][4];
  	
  	/** when the CPU is intel and it supports leaf 0Bh (Extended Topology
  	    enumeration leaf), this stores the result of CPUID with 
  	    eax = 11 and ecx = 0, 1, 2... */
  	uint32_t intel_fn11[MAX_INTELFN11_LEVEL][4];
  };
  
  /**
   * @brief This contains the recognized CPU features/info
   */
  struct cpu_id_t {
  	/** contains the CPU vendor string, e.g. "GenuineIntel" */
  	char vendor_str[VENDOR_STR_MAX];
  	
  	/** contains the brand string, e.g. "Intel(R) Xeon(TM) CPU 2.40GHz" */
  	char brand_str[BRAND_STR_MAX];
  	
  	/** contains the recognized CPU vendor */
  	cpu_vendor_t vendor;
  	
  	/**
  	 * contain CPU flags. Used to test for features. See
  	 * the CPU_FEATURE_* macros below. @see Features
  	 */
  	uint8_t flags[CPU_FLAGS_MAX];
  	
  	/** CPU family */
  	int32_t family;
  	
  	/** CPU model */
  	int32_t model;
  	
  	/** CPU stepping */
  	int32_t stepping;
  	
  	/** CPU extended family */
  	int32_t ext_family;
  	
  	/** CPU extended model */
  	int32_t ext_model;
  	
  	/** Number of CPU cores on the current processor */
  	int32_t num_cores;
  	
  	/**
  	 * Number of logical processors on the current processor.
  	 * Could be more than the number of physical cores,
  	 * e.g. when the processor has HyperThreading.
  	 */
  	int32_t num_logical_cpus;
  	
  	/**
  	 * The total number of logical processors.
  	 *
  	 * This is num_logical_cpus * {total physical processors in the system}
  	 *
  	 * If you're writing a multithreaded program and you want to run it on
  	 * all CPUs, this is the number of threads you need.
  	 */
  	int32_t total_logical_cpus;
  	
  	/**
  	 * L1 data cache size in KB. Could be zero, if the CPU lacks cache.
  	 * If the size cannot be determined, it will be -1.
  	 */
  	int32_t l1_data_cache;
  	
  	/**
  	 * L1 instruction cache size in KB. Could be zero, if the CPU lacks
  	 * cache. If the size cannot be determined, it will be -1.
  	 * @note On some Intel CPUs, whose instruction cache is in fact
  	 * a trace cache, the size will be expressed in K uOps.
  	 */
  	int32_t l1_instruction_cache;
  	
  	/**
  	 * L2 cache size in KB. Could be zero, if the CPU lacks L2 cache.
  	 * If the size of the cache could not be determined, it will be -1
  	 */
  	int32_t l2_cache;
  	
  	/** L3 cache size in KB. Zero on most systems */
  	int32_t l3_cache;
  	
  	/** Cache associativity for the L1 data cache. -1 if undetermined */
  	int32_t l1_assoc;
  	
  	/** Cache associativity for the L2 cache. -1 if undetermined */
  	int32_t l2_assoc;
  	
  	/** Cache associativity for the L3 cache. -1 if undetermined */
  	int32_t l3_assoc;
  	
  	/** Cache-line size for L1 data cache. -1 if undetermined */
  	int32_t l1_cacheline;
  	
  	/** Cache-line size for L2 cache. -1 if undetermined */
  	int32_t l2_cacheline;
  	
  	/** Cache-line size for L3 cache. -1 if undetermined */
  	int32_t l3_cacheline;
  	
  	/**
  	 * The brief and human-friendly CPU codename, which was recognized.<br>
  	 * Examples:
  	 * @code
  	 * +--------+--------+-------+-------+-------+---------------------------------------+-----------------------+
  	 * | Vendor | Family | Model | Step. | Cache |       Brand String                    | cpu_id_t.cpu_codename |
  	 * +--------+--------+-------+-------+-------+---------------------------------------+-----------------------+
  	 * | AMD    |      6 |     8 |     0 |   256 | (not available - will be ignored)     | "K6-2"                |
  	 * | Intel  |     15 |     2 |     5 |   512 | "Intel(R) Xeon(TM) CPU 2.40GHz"       | "Xeon (Prestonia)"    |
  	 * | Intel  |      6 |    15 |    11 |  4096 | "Intel(R) Core(TM)2 Duo CPU E6550..." | "Conroe (Core 2 Duo)" |
  	 * | AMD    |     15 |    35 |     2 |  1024 | "Dual Core AMD Opteron(tm) Proces..." | "Opteron (Dual Core)" |
  	 * +--------+--------+-------+-------+-------+---------------------------------------+-----------------------+
  	 * @endcode
  	 */
  	char cpu_codename[64];
  	
  	/** SSE execution unit size (64 or 128; -1 if N/A) */
  	int32_t sse_size;
  	
  	/**
  	 * contain miscellaneous detection information. Used to test about specifics of
  	 * certain detected features. See CPU_HINT_* macros below. @see Hints
  	 */
  	uint8_t detection_hints[CPU_HINTS_MAX];
  };
  
  /**
   * @brief CPU feature identifiers
   *
   * Usage:
   * @code
   * ...
   * struct cpu_raw_data_t raw;
   * struct cpu_id_t id;
   * if (cpuid_get_raw_data(&raw) == 0 && cpu_identify(&raw, &id) == 0) {
   *     if (id.flags[CPU_FEATURE_SSE2]) {
   *         // The CPU has SSE2...
   *         ...
   *     } else {
   *         // no SSE2
   *     }
   * } else {
   *   // processor cannot be determined.
   * }
   * @endcode
   */
  typedef enum {
  	CPU_FEATURE_FPU = 0,	/*!< Floating point unit */
  	CPU_FEATURE_VME,	/*!< Virtual mode extension */
  	CPU_FEATURE_DE,		/*!< Debugging extension */
  	CPU_FEATURE_PSE,	/*!< Page size extension */
  	CPU_FEATURE_TSC,	/*!< Time-stamp counter */
  	CPU_FEATURE_MSR,	/*!< Model-specific regsisters, RDMSR/WRMSR supported */
  	CPU_FEATURE_PAE,	/*!< Physical address extension */
  	CPU_FEATURE_MCE,	/*!< Machine check exception */
  	CPU_FEATURE_CX8,	/*!< CMPXCHG8B instruction supported */
  	CPU_FEATURE_APIC,	/*!< APIC support */
  	CPU_FEATURE_MTRR,	/*!< Memory type range registers */
  	CPU_FEATURE_SEP,	/*!< SYSENTER / SYSEXIT instructions supported */
  	CPU_FEATURE_PGE,	/*!< Page global enable */
  	CPU_FEATURE_MCA,	/*!< Machine check architecture */
  	CPU_FEATURE_CMOV,	/*!< CMOVxx instructions supported */
  	CPU_FEATURE_PAT,	/*!< Page attribute table */
  	CPU_FEATURE_PSE36,	/*!< 36-bit page address extension */
  	CPU_FEATURE_PN,		/*!< Processor serial # implemented (Intel P3 only) */
  	CPU_FEATURE_CLFLUSH,	/*!< CLFLUSH instruction supported */
  	CPU_FEATURE_DTS,	/*!< Debug store supported */
  	CPU_FEATURE_ACPI,	/*!< ACPI support (power states) */
  	CPU_FEATURE_MMX,	/*!< MMX instruction set supported */
  	CPU_FEATURE_FXSR,	/*!< FXSAVE / FXRSTOR supported */
  	CPU_FEATURE_SSE,	/*!< Streaming-SIMD Extensions (SSE) supported */
  	CPU_FEATURE_SSE2,	/*!< SSE2 instructions supported */
  	CPU_FEATURE_SS,		/*!< Self-snoop */
  	CPU_FEATURE_HT,		/*!< Hyper-threading supported (but might be disabled) */
  	CPU_FEATURE_TM,		/*!< Thermal monitor */
  	CPU_FEATURE_IA64,	/*!< IA64 supported (Itanium only) */
  	CPU_FEATURE_PBE,	/*!< Pending-break enable */
  	CPU_FEATURE_PNI,	/*!< PNI (SSE3) instructions supported */
  	CPU_FEATURE_PCLMUL,	/*!< PCLMULQDQ instruction supported */
  	CPU_FEATURE_DTS64,	/*!< 64-bit Debug store supported */
  	CPU_FEATURE_MONITOR,	/*!< MONITOR / MWAIT supported */
  	CPU_FEATURE_DS_CPL,	/*!< CPL Qualified Debug Store */
  	CPU_FEATURE_VMX,	/*!< Virtualization technology supported */
  	CPU_FEATURE_SMX,	/*!< Safer mode exceptions */
  	CPU_FEATURE_EST,	/*!< Enhanced SpeedStep */
  	CPU_FEATURE_TM2,	/*!< Thermal monitor 2 */
  	CPU_FEATURE_SSSE3,	/*!< SSSE3 instructionss supported (this is different from SSE3!) */
  	CPU_FEATURE_CID,	/*!< Context ID supported */
  	CPU_FEATURE_CX16,	/*!< CMPXCHG16B instruction supported */
  	CPU_FEATURE_XTPR,	/*!< Send Task Priority Messages disable */
  	CPU_FEATURE_PDCM,	/*!< Performance capabilities MSR supported */
  	CPU_FEATURE_DCA,	/*!< Direct cache access supported */
  	CPU_FEATURE_SSE4_1,	/*!< SSE 4.1 instructions supported */
  	CPU_FEATURE_SSE4_2,	/*!< SSE 4.2 instructions supported */
  	CPU_FEATURE_SYSCALL,	/*!< SYSCALL / SYSRET instructions supported */
  	CPU_FEATURE_XD,		/*!< Execute disable bit supported */
  	CPU_FEATURE_MOVBE,	/*!< MOVBE instruction supported */
  	CPU_FEATURE_POPCNT,	/*!< POPCNT instruction supported */
  	CPU_FEATURE_AES,	/*!< AES* instructions supported */
  	CPU_FEATURE_XSAVE,	/*!< XSAVE/XRSTOR/etc instructions supported */
  	CPU_FEATURE_OSXSAVE,	/*!< non-privileged copy of OSXSAVE supported */
  	CPU_FEATURE_AVX,	/*!< Advanced vector extensions supported */
  	CPU_FEATURE_MMXEXT,	/*!< AMD MMX-extended instructions supported */
  	CPU_FEATURE_3DNOW,	/*!< AMD 3DNow! instructions supported */
  	CPU_FEATURE_3DNOWEXT,	/*!< AMD 3DNow! extended instructions supported */
  	CPU_FEATURE_NX,		/*!< No-execute bit supported */
  	CPU_FEATURE_FXSR_OPT,	/*!< FFXSR: FXSAVE and FXRSTOR optimizations */
  	CPU_FEATURE_RDTSCP,	/*!< RDTSCP instruction supported (AMD-only) */
  	CPU_FEATURE_LM,		/*!< Long mode (x86_64/EM64T) supported */
  	CPU_FEATURE_LAHF_LM,	/*!< LAHF/SAHF supported in 64-bit mode */
  	CPU_FEATURE_CMP_LEGACY,	/*!< core multi-processing legacy mode */
  	CPU_FEATURE_SVM,	/*!< AMD Secure virtual machine */
  	CPU_FEATURE_ABM,	/*!< LZCNT instruction support */
  	CPU_FEATURE_MISALIGNSSE,/*!< Misaligned SSE supported */
  	CPU_FEATURE_SSE4A,	/*!< SSE 4a from AMD */
  	CPU_FEATURE_3DNOWPREFETCH,	/*!< PREFETCH/PREFETCHW support */
  	CPU_FEATURE_OSVW,	/*!< OS Visible Workaround (AMD) */
  	CPU_FEATURE_IBS,	/*!< Instruction-based sampling */
  	CPU_FEATURE_SSE5,	/*!< SSE 5 instructions supported (deprecated, will never be 1) */
  	CPU_FEATURE_SKINIT,	/*!< SKINIT / STGI supported */
  	CPU_FEATURE_WDT,	/*!< Watchdog timer support */
  	CPU_FEATURE_TS,		/*!< Temperature sensor */
  	CPU_FEATURE_FID,	/*!< Frequency ID control */
  	CPU_FEATURE_VID,	/*!< Voltage ID control */
  	CPU_FEATURE_TTP,	/*!< THERMTRIP */
  	CPU_FEATURE_TM_AMD,	/*!< AMD-specified hardware thermal control */
  	CPU_FEATURE_STC,	/*!< Software thermal control */
  	CPU_FEATURE_100MHZSTEPS,/*!< 100 MHz multiplier control */
  	CPU_FEATURE_HWPSTATE,	/*!< Hardware P-state control */
  	CPU_FEATURE_CONSTANT_TSC,	/*!< TSC ticks at constant rate */
  	CPU_FEATURE_XOP,	/*!< The XOP instruction set (same as the old CPU_FEATURE_SSE5) */
  	CPU_FEATURE_FMA3,	/*!< The FMA3 instruction set */
  	CPU_FEATURE_FMA4,	/*!< The FMA4 instruction set */
  	CPU_FEATURE_TBM,	/*!< Trailing bit manipulation instruction support */
  	CPU_FEATURE_F16C,	/*!< 16-bit FP convert instruction support */
  	CPU_FEATURE_RDRAND,     /*!< RdRand instruction */
  	CPU_FEATURE_X2APIC,     /*!< x2APIC, APIC_BASE.EXTD, MSRs 0000_0800h...0000_0BFFh 64-bit ICR (+030h but not +031h), no DFR (+00Eh), SELF_IPI (+040h) also see standard level 0000_000Bh */
  	CPU_FEATURE_CPB,	/*!< Core performance boost */
  	CPU_FEATURE_APERFMPERF,	/*!< MPERF/APERF MSRs support */
  	CPU_FEATURE_PFI,	/*!< Processor Feedback Interface support */
  	CPU_FEATURE_PA,		/*!< Processor accumulator */
  	CPU_FEATURE_AVX2,	/*!< AVX2 instructions */
  	/* termination: */
  	NUM_CPU_FEATURES,
  } cpu_feature_t;
  
  /**
   * @brief CPU detection hints identifiers
   *
   * Usage: similar to the flags usage
   */
  typedef enum {
  	CPU_HINT_SSE_SIZE_AUTH = 0,	/*!< SSE unit size is authoritative (not only a Family/Model guesswork, but based on an actual CPUID bit) */
  	/* termination */
  	NUM_CPU_HINTS,
  } cpu_hint_t;
  
  /**
   * @brief Describes common library error codes
   */
  typedef enum {
  	ERR_OK       =  0,	/*!< "No error" */
  	ERR_NO_CPUID = -1,	/*!< "CPUID instruction is not supported" */
  	ERR_NO_RDTSC = -2,	/*!< "RDTSC instruction is not supported" */
  	ERR_NO_MEM   = -3,	/*!< "Memory allocation failed" */
  	ERR_OPEN     = -4,	/*!< "File open operation failed" */
  	ERR_BADFMT   = -5,	/*!< "Bad file format" */
  	ERR_NOT_IMP  = -6,	/*!< "Not implemented" */
  	ERR_CPU_UNKN = -7,	/*!< "Unsupported processor" */
  	ERR_NO_RDMSR = -8,	/*!< "RDMSR instruction is not supported" */
  	ERR_NO_DRIVER= -9,	/*!< "RDMSR driver error (generic)" */
  	ERR_NO_PERMS = -10,	/*!< "No permissions to install RDMSR driver" */
  	ERR_EXTRACT  = -11,	/*!< "Cannot extract RDMSR driver (read only media?)" */
  	ERR_HANDLE   = -12,	/*!< "Bad handle" */
  	ERR_INVMSR   = -13,     /*!< "Invalid MSR" */
  } cpu_error_t;
  
  /**
   * @brief Internal structure, used in cpu_tsc_mark, cpu_tsc_unmark and
   *        cpu_clock_by_mark
   */
  struct cpu_mark_t {
  	uint64_t tsc;		/*!< Time-stamp from RDTSC */
  	uint64_t sys_clock;	/*!< In microsecond resolution */
  };
  
  /**
   * @brief Returns the total number of CPUs even if CPUID is not present
   * @retval Number of CPUs available
   */
  int cpuid_get_total_cpus(void);
  
  /**
   * @brief Checks if the CPUID instruction is supported
   * @retval 1 if CPUID is present
   * @retval 0 the CPU doesn't have CPUID.
   */
  int cpuid_present(void);
  
  /**
   * @brief Executes the CPUID instruction
   * @param eax - the value of the EAX register when executing CPUID
   * @param regs - the results will be stored here. regs[0] = EAX, regs[1] = EBX, ...
   * @note CPUID will be executed with EAX set to the given value and EBX, ECX,
   *       EDX set to zero.
   */
  void cpu_exec_cpuid(uint32_t eax, uint32_t* regs);
  
  /**
   * @brief Executes the CPUID instruction with the given input registers
   * @note This is just a bit more generic version of cpu_exec_cpuid - it allows
   *       you to control all the registers.
   * @param regs - Input/output. Prior to executing CPUID, EAX, EBX, ECX and
   *               EDX will be set to regs[0], regs[1], regs[2] and regs[3].
   *               After CPUID, this array will contain the results.
   */
  void cpu_exec_cpuid_ext(uint32_t* regs);
  
  /**
   * @brief Obtains the raw CPUID data from the current CPU
   * @param data - a pointer to cpu_raw_data_t structure
   * @returns zero if successful, and some negative number on error.
   *          The error message can be obtained by calling \ref cpuid_error.
   *          @see cpu_error_t
   */
  int cpuid_get_raw_data(struct cpu_raw_data_t* data);
  
  /**
   * @brief Writes the raw CPUID data to a text file
   * @param data - a pointer to cpu_raw_data_t structure
   * @param filename - the path of the file, where the serialized data should be
   *                   written. If empty, stdout will be used.
   * @note This is intended primarily for debugging. On some processor, which is
   *       not currently supported or not completely recognized by cpu_identify,
   *       one can still successfully get the raw data and write it to a file.
   *       libcpuid developers can later import this file and debug the detection
   *       code as if running on the actual hardware.
   *       The file is simple text format of "something=value" pairs. Version info
   *       is also written, but the format is not intended to be neither backward-
   *       nor forward compatible.
   * @returns zero if successful, and some negative number on error.
   *          The error message can be obtained by calling \ref cpuid_error.
   *          @see cpu_error_t
   */
  int cpuid_serialize_raw_data(struct cpu_raw_data_t* data, const char* filename);
  
  /**
   * @brief Reads raw CPUID data from file
   * @param data - a pointer to cpu_raw_data_t structure. The deserialized data will
   *               be written here.
   * @param filename - the path of the file, containing the serialized raw data.
   *                   If empty, stdin will be used.
   * @note This function may fail, if the file is created by different version of
   *       the library. Also, see the notes on cpuid_serialize_raw_data.
   * @returns zero if successful, and some negative number on error.
   *          The error message can be obtained by calling \ref cpuid_error.
   *          @see cpu_error_t
  */
  int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename);
  
  /**
   * @brief Identifies the CPU
   * @param raw - Input - a pointer to the raw CPUID data, which is obtained
   *              either by cpuid_get_raw_data or cpuid_deserialize_raw_data.
   *              Can also be NULL, in which case the functions calls
   *              cpuid_get_raw_data itself.
   * @param data - Output - the decoded CPU features/info is written here.
   * @note The function will not fail, even if some of the information
   *       cannot be obtained. Even when the CPU is new and thus unknown to
   *       libcpuid, some generic info, such as "AMD K9 family CPU" will be
   *       written to data.cpu_codename, and most other things, such as the
   *       CPU flags, cache sizes, etc. should be detected correctly anyway.
   *       However, the function CAN fail, if the CPU is completely alien to
   *       libcpuid.
   * @note While cpu_identify() and cpuid_get_raw_data() are fast for most
   *       purposes, running them several thousand times per second can hamper
   *       performance significantly. Specifically, avoid writing "cpu feature
   *       checker" wrapping function, which calls cpu_identify and returns the
   *       value of some flag, if that function is going to be called frequently.
   * @returns zero if successful, and some negative number on error.
   *          The error message can be obtained by calling \ref cpuid_error.
   *          @see cpu_error_t
   */
  int cpu_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data);
  
  /**
   * @brief Returns the short textual representation of a CPU flag
   * @param feature - the feature, whose textual representation is wanted.
   * @returns a constant string like "fpu", "tsc", "sse2", etc.
   * @note the names of the returned flags are compatible with those from
   *       /proc/cpuinfo in Linux, with the exception of `tm_amd'
   */
  const char* cpu_feature_str(cpu_feature_t feature);
  
  /**
   * @brief Returns textual description of the last error
   *
   * libcpuid stores an `errno'-style error status, whose description
   * can be obtained with this function.
   * @note This function is not thread-safe
   * @see cpu_error_t
   */
  const char* cpuid_error(void);
  
  /**
   * @brief Executes RDTSC
   *
   * The RDTSC (ReaD Time Stamp Counter) instruction gives access to an
   * internal 64-bit counter, which usually increments at each clock cycle.
   * This can be used for various timing routines, and as a very precise
   * clock source. It is set to zero on system startup. Beware that may not
   * increment at the same frequency as the CPU. Consecutive calls of RDTSC
   * are, however, guaranteed to return monotonically-increasing values.
   *
   * @param result - a pointer to a 64-bit unsigned integer, where the TSC value
   *                 will be stored
   *
   * @note  If 100% compatibility is a concern, you must first check if the
   * RDTSC instruction is present (if it is not, your program will crash
   * with "invalid opcode" exception). Only some very old processors (i486,
   * early AMD K5 and some Cyrix CPUs) lack that instruction - they should
   * have become exceedingly rare these days. To verify RDTSC presence,
   * run cpu_identify() and check flags[CPU_FEATURE_TSC].
   *
   * @note The monotonically increasing nature of the TSC may be violated
   * on SMP systems, if their TSC clocks run at different rate. If the OS
   * doesn't account for that, the TSC drift may become arbitrary large.
   */
  void cpu_rdtsc(uint64_t* result);
  
  /**
   * @brief Store TSC and timing info
   *
   * This function stores the current TSC value and current
   * time info from a precise OS-specific clock source in the cpu_mark_t
   * structure. The sys_clock field contains time with microsecond resolution.
   * The values can later be used to measure time intervals, number of clocks,
   * FPU frequency, etc.
   * @see cpu_rdtsc
   *
   * @param mark [out] - a pointer to a cpu_mark_t structure
   */
  void cpu_tsc_mark(struct cpu_mark_t* mark);
  
  /**
   * @brief Calculate TSC and timing difference
   *
   * @param mark - input/output: a pointer to a cpu_mark_t sturcture, which has
   *               already been initialized by cpu_tsc_mark. The difference in
   *               TSC and time will be written here.
   *
   * This function calculates the TSC and time difference, by obtaining the
   * current TSC and timing values and subtracting the contents of the `mark'
   * structure from them. Results are written in the same structure.
   *
   * Example:
   * @code
   * ...
   * struct cpu_mark_t mark;
   * cpu_tsc_mark(&mark);
   * foo();
   * cpu_tsc_unmark(&mark);
   * printf("Foo finished. Executed in %llu cycles and %llu usecs\n",
   *        mark.tsc, mark.sys_clock);
   * ...
   * @endcode
   */
  void cpu_tsc_unmark(struct cpu_mark_t* mark);
  
  /**
   * @brief Calculates the CPU clock
   *
   * @param mark - pointer to a cpu_mark_t structure, which has been initialized
   *   with cpu_tsc_mark and later `stopped' with cpu_tsc_unmark.
   *
   * @note For reliable results, the marked time interval should be at least about
   * 10 ms.
   *
   * @returns the CPU clock frequency, in MHz. Due to measurement error, it will
   * differ from the true value in a few least-significant bits. Accuracy depends
   * on the timing interval - the more, the better. If the timing interval is
   * insufficient, the result is -1. Also, see the comment on cpu_clock_measure
   * for additional issues and pitfalls in using RDTSC for CPU frequency
   * measurements.
   */
  int cpu_clock_by_mark(struct cpu_mark_t* mark);
  
  /**
   * @brief Returns the CPU clock, as reported by the OS
   *
   * This function uses OS-specific functions to obtain the CPU clock. It may
   * differ from the true clock for several reasons:<br><br>
   *
   * i) The CPU might be in some power saving state, while the OS reports its
   *    full-power frequency, or vice-versa.<br>
   * ii) In some cases you can raise or lower the CPU frequency with overclocking
   *     utilities and the OS will not notice.
   *
   * @returns the CPU clock frequency in MHz. If the OS is not (yet) supported
   * or lacks the necessary reporting machinery, the return value is -1
   */
  int cpu_clock_by_os(void);
  
  /**
   * @brief Measure the CPU clock frequency
   *
   * @param millis - How much time to waste in the busy-wait cycle. In millisecs.
   *                 Useful values 10 - 1000
   * @param quad_check - Do a more thorough measurement if nonzero
   *                     (see the explanation).
   *
   * The function performs a busy-wait cycle for the given time and calculates
   * the CPU frequency by the difference of the TSC values. The accuracy of the
   * calculation depends on the length of the busy-wait cycle: more is better,
   * but 100ms should be enough for most purposes.
   *
   * While this will calculate the CPU frequency correctly in most cases, there are
   * several reasons why it might be incorrect:<br>
   *
   * i) RDTSC doesn't guarantee it will run at the same clock as the CPU.
   *    Apparently there aren't CPUs at the moment, but still, there's no
   *    guarantee.<br>
   * ii) The CPU might be in a low-frequency power saving mode, and the CPU
   *     might be switched to higher frequency at any time. If this happens
   *     during the measurement, the result can be anywhere between the
   *     low and high frequencies. Also, if you're interested in the
   *     high frequency value only, this function might return the low one
   *     instead.<br>
   * iii) On SMP systems exhibiting TSC drift (see \ref cpu_rdtsc)
   *
   * the quad_check option will run four consecutive measurements and
   * then return the average of the two most-consistent results. The total
   * runtime of the function will still be `millis' - consider using
   * a bit more time for the timing interval.
   *
   * Finally, for benchmarking / CPU intensive applications, the best strategy is
   * to use the cpu_tsc_mark() / cpu_tsc_unmark() / cpu_clock_by_mark() method.
   * Begin by mark()-ing about one second after application startup (allowing the
   * power-saving manager to kick in and rise the frequency during that time),
   * then unmark() just before application finishing. The result will most
   * acurately represent at what frequency your app was running.
   *
   * @returns the CPU clock frequency in MHz (within some measurement error
   * margin). If RDTSC is not supported, the result is -1.
   */
  int cpu_clock_measure(int millis, int quad_check);
  
  /**
   * @brief Measure the CPU clock frequency using instruction-counting
   *
   * @param millis - how much time to allocate for each run, in milliseconds
   * @param runs - how many runs to perform
   *
   * The function performs a busy-wait cycle using a known number of "heavy" (SSE)
   * instructions. These instructions run at (more or less guaranteed) 1 IPC rate,
   * so by running a busy loop for a fixed amount of time, and measuring the
   * amount of instructions done, the CPU clock is accurately measured.
   *
   * Of course, this function is still affected by the power-saving schemes, so
   * the warnings as of cpu_clock_measure() still apply. However, this function is
   * immune to problems with detection, related to the Intel Nehalem's "Turbo"
   * mode, where the internal clock is raised, but the RDTSC rate is unaffected.
   *
   * The function will run for about (millis * runs) milliseconds.
   * You can make only a single busy-wait run (runs == 1); however, this can
   * be affected by task scheduling (which will break the counting), so allowing
   * more than one run is recommended. As run length is not imperative for
   * accurate readings (e.g., 50ms is sufficient), you can afford a lot of short
   * runs, e.g. 10 runs of 50ms or 20 runs of 25ms.
   *
   * Recommended values - millis = 50, runs = 4. For more robustness,
   * increase the number of runs.
   * 
   * NOTE: on Bulldozer and later CPUs, the busy-wait cycle runs at 1.4 IPC, thus
   * the results are skewed. This is corrected internally by dividing the resulting
   * value by 1.4.
   * However, this only occurs if the thread is executed on a single CMT
   * module - if there are other threads competing for resources, the results are
   * unpredictable. Make sure you run cpu_clock_by_ic() on a CPU that is free from
   * competing threads, or if there are such threads, they shouldn't exceed the
   * number of modules. On a Bulldozer X8, that means 4 threads.
   *
   * @returns the CPU clock frequency in MHz (within some measurement error
   * margin). If SSE is not supported, the result is -1. If the input parameters
   * are incorrect, or some other internal fault is detected, the result is -2.
   */
  int cpu_clock_by_ic(int millis, int runs);
  
  /**
   * @brief Get the CPU clock frequency (all-in-one method)
   *
   * This is an all-in-one method for getting the CPU clock frequency.
   * It tries to use the OS for that. If the OS doesn't have this info, it
   * uses cpu_clock_measure with 200ms time interval and quadruple checking.
   *
   * @returns the CPU clock frequency in MHz. If every possible method fails,
   * the result is -1.
   */
  int cpu_clock(void);
  
  /**
   * @brief Returns the libcpuid version
   *
   * @returns the string representation of the libcpuid version, like "0.1.1"
   */
  const char* cpuid_lib_version(void);
  
  typedef void (*libcpuid_warn_fn_t) (const char *msg);
  /**
   * @brief Sets the warning print function
   *
   * In some cases, the internal libcpuid machinery would like to emit useful
   * debug warnings. By default, these warnings are written to stderr. However,
   * you can set a custom function that will receive those warnings.
   *
   * @param warn_fun - the warning function you want to set. If NULL, warnings
   *                   are disabled. The function takes const char* argument.
   *
   * @returns the current warning function. You can use the return value to
   * keep the previous warning function and restore it at your discretion.
   */
  libcpuid_warn_fn_t cpuid_set_warn_function(libcpuid_warn_fn_t warn_fun);
  
  /**
   * @brief Sets the verbosiness level
   *
   * When the verbosiness level is above zero, some functions might print
   * diagnostic information about what are they doing. The higher the level is,
   * the more detail is printed. Level zero is guaranteed to omit all such
   * output. The output is written using the same machinery as the warnings,
   * @see cpuid_set_warn_function()
   *
   * @param level the desired verbosiness level. Useful values 0..2 inclusive
   */
  void cpuid_set_verbosiness_level(int level);
  
  
  /**
   * @brief a structure that holds a list of processor names
   */
  struct cpu_list_t {
  	/** Number of entries in the list */
  	int num_entries;
  	/** Pointers to names. There will be num_entries of them */
  	char **names;
  };
  
  /**
   * @brief Gets a list of all known CPU names from a specific vendor.
   *
   * This function compiles a list of all known CPU (code)names
   * (i.e. the possible values of cpu_id_t::cpu_codename) for the given vendor.
   *
   * There are about 100 entries for Intel and AMD, and a few for the other
   * vendors. The list is written out in approximate chronological introduction
   * order of the parts.
   *
   * @param vendor the vendor to be queried
   * @param list [out] the resulting list will be written here.
   * NOTE: As the memory is dynamically allocated, be sure to call
   *       cpuid_free_cpu_list() after you're done with the data
   * @see cpu_list_t
   */
  void cpuid_get_cpu_list(cpu_vendor_t vendor, struct cpu_list_t* list);
  
  /**
   * @brief Frees a CPU list
   *
   * This function deletes all the memory associated with a CPU list, as obtained
   * by cpuid_get_cpu_list()
   *
   * @param list - the list to be free()'d.
   */
  void cpuid_free_cpu_list(struct cpu_list_t* list);
  
  /**
   * @brief Starts/opens a driver, needed to read MSRs (Model Specific Registers)
   *
   * On systems that support it, this function will create a temporary
   * system driver, that has privileges to execute the RDMSR instruction.
   * After the driver is created, you can read MSRs by calling \ref cpu_rdmsr
   *
   * @returns a handle to the driver on success, and NULL on error.
   *          The error message can be obtained by calling \ref cpuid_error.
   *          @see cpu_error_t
   */
  struct msr_driver_t;
  struct msr_driver_t* cpu_msr_driver_open(void);
  
  /**
   * @brief Reads a Model-Specific Register (MSR)
   *
   * If the CPU has MSRs (as indicated by the CPU_FEATURE_MSR flag), you can
   * read a MSR with the given index by calling this function.
   *
   * There are several prerequisites you must do before reading MSRs:
   * 1) You must ensure the CPU has RDMSR. Check the CPU_FEATURE_MSR flag
   *    in cpu_id_t::flags
   * 2) You must ensure that the CPU implements the specific MSR you intend to
   *    read.
   * 3) You must open a MSR-reader driver. RDMSR is a privileged instruction and
   *    needs ring-0 access in order to work. This temporary driver is created
   *    by calling \ref cpu_msr_driver_open
   *
   * @param handle - a handle to the MSR reader driver, as created by
   *                 cpu_msr_driver_open
   * @param msr_index - the numeric ID of the MSR you want to read
   * @param result - a pointer to a 64-bit integer, where the MSR value is stored
   *
   * @returns zero if successful, and some negative number on error.
   *          The error message can be obtained by calling \ref cpuid_error.
   *          @see cpu_error_t
   */
  int cpu_rdmsr(struct msr_driver_t* handle, int msr_index, uint64_t* result);
  
  
  typedef enum {
  	INFO_MPERF,                /*!< Maximum performance frequency clock. This
                                      is a counter, which increments as a
                                      proportion of the actual processor speed */
  	INFO_APERF,                /*!< Actual performance frequency clock. This
                                      accumulates the core clock counts when the
                                      core is active. */
  	INFO_CUR_MULTIPLIER,       /*!< Current CPU:FSB ratio, multiplied by 100.
                                      e.g., a CPU:FSB value of 18.5 reads as
                                      1850. */
  	INFO_MAX_MULTIPLIER,       /*!< Maxumum CPU:FSB ratio for this CPU,
                                      multiplied by 100 */
  	INFO_TEMPERATURE,          /*!< The current core temperature in Celsius */
  	INFO_THROTTLING,           /*!< 1 if the current logical processor is
                                      throttling. 0 if it is running normally. */
  } cpu_msrinfo_request_t;
  
  /**
   * @brief Reads extended CPU information from Model-Specific Registers.
   * @param handle - a handle to an open MSR driver, @see cpu_msr_driver_open
   * @param which - which info field should be returned. A list of
   *                available information entities is listed in the
   *                cpu_msrinfo_request_t enum.
   * @retval - if the requested information is available for the current
   *           processor model, the respective value is returned.
   *           if no information is available, or the CPU doesn't support
   *           the query, the special value CPU_INVALID_VALUE is returned
   */
  int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which);
  #define CPU_INVALID_VALUE 0x3fffffff
  
  /**
   * @brief Closes an open MSR driver
   *
   * This function unloads the MSR driver opened by cpu_msr_driver_open and
   * frees any resources associated with it.
   *
   * @param handle - a handle to the MSR reader driver, as created by
   *                 cpu_msr_driver_open
   *
   * @returns zero if successful, and some negative number on error.
   *          The error message can be obtained by calling \ref cpuid_error.
   *          @see cpu_error_t
   */
  int cpu_msr_driver_close(struct msr_driver_t* handle);
  
  #ifdef __cplusplus
  }; /* extern "C" */
  #endif
  
  
  /** @} */
  
  #endif /* __LIBCPUID_H__ */
  