diff --git a/src/3rdparty/libcpuid/CMakeLists.txt b/src/3rdparty/libcpuid/CMakeLists.txt index 51eab1d3..a3396d1d 100644 --- a/src/3rdparty/libcpuid/CMakeLists.txt +++ b/src/3rdparty/libcpuid/CMakeLists.txt @@ -6,25 +6,29 @@ add_definitions(/DVERSION="0.4.0") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Os") set(HEADERS + amd_code_t.h + asm-bits.h + intel_code_t.h libcpuid.h - libcpuid_types.h libcpuid_constants.h libcpuid_internal.h - amd_code_t.h - intel_code_t.h + libcpuid_types.h + libcpuid_util.h + rdtsc.h recog_amd.h recog_intel.h - asm-bits.h - libcpuid_util.h ) set(SOURCES - cpuid_main.c asm-bits.c + cpuid_main.c + libcpuid_util.c + msrdriver.c + rdmsr.c + rdtsc.c recog_amd.c recog_intel.c - libcpuid_util.c - ) + ) if (CMAKE_CL_64) enable_language(ASM_MASM) diff --git a/src/3rdparty/libcpuid/cpuid_main.c b/src/3rdparty/libcpuid/cpuid_main.c index f22c7dd6..504c0af8 100644 --- a/src/3rdparty/libcpuid/cpuid_main.c +++ b/src/3rdparty/libcpuid/cpuid_main.c @@ -46,6 +46,11 @@ int set_error(cpu_error_t err) return (int) err; } +static void raw_data_t_constructor(struct cpu_raw_data_t* raw) +{ + memset(raw, 0, sizeof(struct cpu_raw_data_t)); +} + static void cpu_id_t_constructor(struct cpu_id_t* id) { memset(id, 0, sizeof(struct cpu_id_t)); @@ -55,6 +60,29 @@ static void cpu_id_t_constructor(struct cpu_id_t* id) id->sse_size = -1; } +static int parse_token(const char* expected_token, const char *token, + const char *value, uint32_t array[][4], int limit, int *recognized) +{ + char format[32]; + int veax, vebx, vecx, vedx; + int index; + + if (*recognized) return 1; /* already recognized */ + if (strncmp(token, expected_token, strlen(expected_token))) return 1; /* not what we search for */ + sprintf(format, "%s[%%d]", expected_token); + *recognized = 1; + if (1 == sscanf(token, format, &index) && index >=0 && index < limit) { + if (4 == sscanf(value, "%x%x%x%x", &veax, &vebx, &vecx, &vedx)) { + array[index][0] = veax; + array[index][1] = vebx; + array[index][2] = vecx; + array[index][3] = vedx; + return 1; + } + } + return 0; +} + /* get_total_cpus() system specific code: uses OS routines to determine total number of CPUs */ #ifdef __APPLE__ #include @@ -221,42 +249,42 @@ static void load_features_common(struct cpu_raw_data_t* raw, struct cpu_id_t* da static cpu_vendor_t cpuid_vendor_identify(const uint32_t *raw_vendor, char *vendor_str) { - int i; - cpu_vendor_t vendor = VENDOR_UNKNOWN; - const struct { cpu_vendor_t vendor; char match[16]; } - matchtable[NUM_CPU_VENDORS] = { - /* source: http://www.sandpile.org/ia32/cpuid.htm */ - { VENDOR_INTEL , "GenuineIntel" }, - { VENDOR_AMD , "AuthenticAMD" }, - { VENDOR_CYRIX , "CyrixInstead" }, - { VENDOR_NEXGEN , "NexGenDriven" }, - { VENDOR_TRANSMETA , "GenuineTMx86" }, - { VENDOR_UMC , "UMC UMC UMC " }, - { VENDOR_CENTAUR , "CentaurHauls" }, - { VENDOR_RISE , "RiseRiseRise" }, - { VENDOR_SIS , "SiS SiS SiS " }, - { VENDOR_NSC , "Geode by NSC" }, - }; + int i; + cpu_vendor_t vendor = VENDOR_UNKNOWN; + const struct { cpu_vendor_t vendor; char match[16]; } + matchtable[NUM_CPU_VENDORS] = { + /* source: http://www.sandpile.org/ia32/cpuid.htm */ + { VENDOR_INTEL , "GenuineIntel" }, + { VENDOR_AMD , "AuthenticAMD" }, + { VENDOR_CYRIX , "CyrixInstead" }, + { VENDOR_NEXGEN , "NexGenDriven" }, + { VENDOR_TRANSMETA , "GenuineTMx86" }, + { VENDOR_UMC , "UMC UMC UMC " }, + { VENDOR_CENTAUR , "CentaurHauls" }, + { VENDOR_RISE , "RiseRiseRise" }, + { VENDOR_SIS , "SiS SiS SiS " }, + { VENDOR_NSC , "Geode by NSC" }, + }; - memcpy(vendor_str + 0, &raw_vendor[1], 4); - memcpy(vendor_str + 4, &raw_vendor[3], 4); - memcpy(vendor_str + 8, &raw_vendor[2], 4); - vendor_str[12] = 0; + memcpy(vendor_str + 0, &raw_vendor[1], 4); + memcpy(vendor_str + 4, &raw_vendor[3], 4); + memcpy(vendor_str + 8, &raw_vendor[2], 4); + vendor_str[12] = 0; - /* Determine vendor: */ - for (i = 0; i < NUM_CPU_VENDORS; i++) - if (!strcmp(vendor_str, matchtable[i].match)) { - vendor = matchtable[i].vendor; - break; - } - return vendor; + /* Determine vendor: */ + for (i = 0; i < NUM_CPU_VENDORS; i++) + if (!strcmp(vendor_str, matchtable[i].match)) { + vendor = matchtable[i].vendor; + break; + } + return vendor; } static int cpuid_basic_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data) { int i, j, basic, xmodel, xfamily, ext; char brandstr[64] = {0}; - data->vendor = cpuid_vendor_identify(raw->basic_cpuid[0], data->vendor_str); + data->vendor = cpuid_vendor_identify(raw->basic_cpuid[0], data->vendor_str); if (data->vendor == VENDOR_UNKNOWN) return set_error(ERR_CPU_UNKN); @@ -292,6 +320,27 @@ static int cpuid_basic_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* dat return set_error(ERR_OK); } +static void make_list_from_string(const char* csv, struct cpu_list_t* list) +{ + int i, n, l, last; + l = (int) strlen(csv); + n = 0; + for (i = 0; i < l; i++) if (csv[i] == ',') n++; + n++; + list->num_entries = n; + list->names = (char**) malloc(sizeof(char*) * n); + last = -1; + n = 0; + for (i = 0; i <= l; i++) if (i == l || csv[i] == ',') { + list->names[n] = (char*) malloc(i - last); + memcpy(list->names[n], &csv[last + 1], i - last - 1); + list->names[n][i - last - 1] = '\0'; + n++; + last = i; + } +} + + /* Interface: */ int cpuid_get_total_cpus(void) @@ -352,6 +401,107 @@ int cpuid_get_raw_data(struct cpu_raw_data_t* data) return set_error(ERR_OK); } +int cpuid_serialize_raw_data(struct cpu_raw_data_t* data, const char* filename) +{ + int i; + FILE *f; + + if (!strcmp(filename, "")) + f = stdout; + else + f = fopen(filename, "wt"); + if (!f) return set_error(ERR_OPEN); + + fprintf(f, "version=%s\n", VERSION); + for (i = 0; i < MAX_CPUID_LEVEL; i++) + fprintf(f, "basic_cpuid[%d]=%08x %08x %08x %08x\n", i, + data->basic_cpuid[i][0], data->basic_cpuid[i][1], + data->basic_cpuid[i][2], data->basic_cpuid[i][3]); + for (i = 0; i < MAX_EXT_CPUID_LEVEL; i++) + fprintf(f, "ext_cpuid[%d]=%08x %08x %08x %08x\n", i, + data->ext_cpuid[i][0], data->ext_cpuid[i][1], + data->ext_cpuid[i][2], data->ext_cpuid[i][3]); + for (i = 0; i < MAX_INTELFN4_LEVEL; i++) + fprintf(f, "intel_fn4[%d]=%08x %08x %08x %08x\n", i, + data->intel_fn4[i][0], data->intel_fn4[i][1], + data->intel_fn4[i][2], data->intel_fn4[i][3]); + for (i = 0; i < MAX_INTELFN11_LEVEL; i++) + fprintf(f, "intel_fn11[%d]=%08x %08x %08x %08x\n", i, + data->intel_fn11[i][0], data->intel_fn11[i][1], + data->intel_fn11[i][2], data->intel_fn11[i][3]); + for (i = 0; i < MAX_INTELFN12H_LEVEL; i++) + fprintf(f, "intel_fn12h[%d]=%08x %08x %08x %08x\n", i, + data->intel_fn12h[i][0], data->intel_fn12h[i][1], + data->intel_fn12h[i][2], data->intel_fn12h[i][3]); + for (i = 0; i < MAX_INTELFN14H_LEVEL; i++) + fprintf(f, "intel_fn14h[%d]=%08x %08x %08x %08x\n", i, + data->intel_fn14h[i][0], data->intel_fn14h[i][1], + data->intel_fn14h[i][2], data->intel_fn14h[i][3]); + + if (strcmp(filename, "")) + fclose(f); + return set_error(ERR_OK); +} + +int cpuid_deserialize_raw_data(struct cpu_raw_data_t* data, const char* filename) +{ + int i, len; + char line[100]; + char token[100]; + char *value; + int syntax; + int cur_line = 0; + int recognized; + FILE *f; + + raw_data_t_constructor(data); + + if (!strcmp(filename, "")) + f = stdin; + else + f = fopen(filename, "rt"); + if (!f) return set_error(ERR_OPEN); + while (fgets(line, sizeof(line), f)) { + ++cur_line; + len = (int) strlen(line); + if (len < 2) continue; + if (line[len - 1] == '\n') + line[--len] = '\0'; + for (i = 0; i < len && line[i] != '='; i++) + if (i >= len && i < 1 && len - i - 1 <= 0) { + fclose(f); + return set_error(ERR_BADFMT); + } + strncpy(token, line, i); + token[i] = '\0'; + value = &line[i + 1]; + /* try to recognize the line */ + recognized = 0; + if (!strcmp(token, "version") || !strcmp(token, "build_date")) { + recognized = 1; + } + syntax = 1; + syntax = syntax && parse_token("basic_cpuid", token, value, data->basic_cpuid, MAX_CPUID_LEVEL, &recognized); + syntax = syntax && parse_token("ext_cpuid", token, value, data->ext_cpuid, MAX_EXT_CPUID_LEVEL, &recognized); + syntax = syntax && parse_token("intel_fn4", token, value, data->intel_fn4, MAX_INTELFN4_LEVEL, &recognized); + syntax = syntax && parse_token("intel_fn11", token, value, data->intel_fn11, MAX_INTELFN11_LEVEL, &recognized); + syntax = syntax && parse_token("intel_fn12h", token, value, data->intel_fn12h, MAX_INTELFN12H_LEVEL, &recognized); + syntax = syntax && parse_token("intel_fn14h", token, value, data->intel_fn14h, MAX_INTELFN14H_LEVEL, &recognized); + if (!syntax) { + warnf("Error: %s:%d: Syntax error\n", filename, cur_line); + fclose(f); + return set_error(ERR_BADFMT); + } + if (!recognized) { + warnf("Warning: %s:%d not understood!\n", filename, cur_line); + } + } + + if (strcmp(filename, "")) + fclose(f); + return set_error(ERR_OK); +} + int cpu_ident_internal(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal) { int r; @@ -383,7 +533,239 @@ int cpu_identify(struct cpu_raw_data_t* raw, struct cpu_id_t* data) return cpu_ident_internal(raw, data, &throwaway); } +const char* cpu_feature_str(cpu_feature_t feature) +{ + const struct { cpu_feature_t feature; const char* name; } + matchtable[] = { + { CPU_FEATURE_FPU, "fpu" }, + { CPU_FEATURE_VME, "vme" }, + { CPU_FEATURE_DE, "de" }, + { CPU_FEATURE_PSE, "pse" }, + { CPU_FEATURE_TSC, "tsc" }, + { CPU_FEATURE_MSR, "msr" }, + { CPU_FEATURE_PAE, "pae" }, + { CPU_FEATURE_MCE, "mce" }, + { CPU_FEATURE_CX8, "cx8" }, + { CPU_FEATURE_APIC, "apic" }, + { CPU_FEATURE_MTRR, "mtrr" }, + { CPU_FEATURE_SEP, "sep" }, + { CPU_FEATURE_PGE, "pge" }, + { CPU_FEATURE_MCA, "mca" }, + { CPU_FEATURE_CMOV, "cmov" }, + { CPU_FEATURE_PAT, "pat" }, + { CPU_FEATURE_PSE36, "pse36" }, + { CPU_FEATURE_PN, "pn" }, + { CPU_FEATURE_CLFLUSH, "clflush" }, + { CPU_FEATURE_DTS, "dts" }, + { CPU_FEATURE_ACPI, "acpi" }, + { CPU_FEATURE_MMX, "mmx" }, + { CPU_FEATURE_FXSR, "fxsr" }, + { CPU_FEATURE_SSE, "sse" }, + { CPU_FEATURE_SSE2, "sse2" }, + { CPU_FEATURE_SS, "ss" }, + { CPU_FEATURE_HT, "ht" }, + { CPU_FEATURE_TM, "tm" }, + { CPU_FEATURE_IA64, "ia64" }, + { CPU_FEATURE_PBE, "pbe" }, + { CPU_FEATURE_PNI, "pni" }, + { CPU_FEATURE_PCLMUL, "pclmul" }, + { CPU_FEATURE_DTS64, "dts64" }, + { CPU_FEATURE_MONITOR, "monitor" }, + { CPU_FEATURE_DS_CPL, "ds_cpl" }, + { CPU_FEATURE_VMX, "vmx" }, + { CPU_FEATURE_SMX, "smx" }, + { CPU_FEATURE_EST, "est" }, + { CPU_FEATURE_TM2, "tm2" }, + { CPU_FEATURE_SSSE3, "ssse3" }, + { CPU_FEATURE_CID, "cid" }, + { CPU_FEATURE_CX16, "cx16" }, + { CPU_FEATURE_XTPR, "xtpr" }, + { CPU_FEATURE_PDCM, "pdcm" }, + { CPU_FEATURE_DCA, "dca" }, + { CPU_FEATURE_SSE4_1, "sse4_1" }, + { CPU_FEATURE_SSE4_2, "sse4_2" }, + { CPU_FEATURE_SYSCALL, "syscall" }, + { CPU_FEATURE_XD, "xd" }, + { CPU_FEATURE_X2APIC, "x2apic"}, + { CPU_FEATURE_MOVBE, "movbe" }, + { CPU_FEATURE_POPCNT, "popcnt" }, + { CPU_FEATURE_AES, "aes" }, + { CPU_FEATURE_XSAVE, "xsave" }, + { CPU_FEATURE_OSXSAVE, "osxsave" }, + { CPU_FEATURE_AVX, "avx" }, + { CPU_FEATURE_MMXEXT, "mmxext" }, + { CPU_FEATURE_3DNOW, "3dnow" }, + { CPU_FEATURE_3DNOWEXT, "3dnowext" }, + { CPU_FEATURE_NX, "nx" }, + { CPU_FEATURE_FXSR_OPT, "fxsr_opt" }, + { CPU_FEATURE_RDTSCP, "rdtscp" }, + { CPU_FEATURE_LM, "lm" }, + { CPU_FEATURE_LAHF_LM, "lahf_lm" }, + { CPU_FEATURE_CMP_LEGACY, "cmp_legacy" }, + { CPU_FEATURE_SVM, "svm" }, + { CPU_FEATURE_SSE4A, "sse4a" }, + { CPU_FEATURE_MISALIGNSSE, "misalignsse" }, + { CPU_FEATURE_ABM, "abm" }, + { CPU_FEATURE_3DNOWPREFETCH, "3dnowprefetch" }, + { CPU_FEATURE_OSVW, "osvw" }, + { CPU_FEATURE_IBS, "ibs" }, + { CPU_FEATURE_SSE5, "sse5" }, + { CPU_FEATURE_SKINIT, "skinit" }, + { CPU_FEATURE_WDT, "wdt" }, + { CPU_FEATURE_TS, "ts" }, + { CPU_FEATURE_FID, "fid" }, + { CPU_FEATURE_VID, "vid" }, + { CPU_FEATURE_TTP, "ttp" }, + { CPU_FEATURE_TM_AMD, "tm_amd" }, + { CPU_FEATURE_STC, "stc" }, + { CPU_FEATURE_100MHZSTEPS, "100mhzsteps" }, + { CPU_FEATURE_HWPSTATE, "hwpstate" }, + { CPU_FEATURE_CONSTANT_TSC, "constant_tsc" }, + { CPU_FEATURE_XOP, "xop" }, + { CPU_FEATURE_FMA3, "fma3" }, + { CPU_FEATURE_FMA4, "fma4" }, + { CPU_FEATURE_TBM, "tbm" }, + { CPU_FEATURE_F16C, "f16c" }, + { CPU_FEATURE_RDRAND, "rdrand" }, + { CPU_FEATURE_CPB, "cpb" }, + { CPU_FEATURE_APERFMPERF, "aperfmperf" }, + { CPU_FEATURE_PFI, "pfi" }, + { CPU_FEATURE_PA, "pa" }, + { CPU_FEATURE_AVX2, "avx2" }, + { CPU_FEATURE_BMI1, "bmi1" }, + { CPU_FEATURE_BMI2, "bmi2" }, + { CPU_FEATURE_HLE, "hle" }, + { CPU_FEATURE_RTM, "rtm" }, + { CPU_FEATURE_AVX512F, "avx512f" }, + { CPU_FEATURE_AVX512DQ, "avx512dq" }, + { CPU_FEATURE_AVX512PF, "avx512pf" }, + { CPU_FEATURE_AVX512ER, "avx512er" }, + { CPU_FEATURE_AVX512CD, "avx512cd" }, + { CPU_FEATURE_SHA_NI, "sha_ni" }, + { CPU_FEATURE_AVX512BW, "avx512bw" }, + { CPU_FEATURE_AVX512VL, "avx512vl" }, + { CPU_FEATURE_SGX, "sgx" }, + { CPU_FEATURE_RDSEED, "rdseed" }, + { CPU_FEATURE_ADX, "adx" }, + }; + unsigned i, n = COUNT_OF(matchtable); + if (n != NUM_CPU_FEATURES) { + warnf("Warning: incomplete library, feature matchtable size differs from the actual number of features.\n"); + } + for (i = 0; i < n; i++) + if (matchtable[i].feature == feature) + return matchtable[i].name; + return ""; +} + +const char* cpuid_error(void) +{ + const struct { cpu_error_t error; const char *description; } + matchtable[] = { + { ERR_OK , "No error"}, + { ERR_NO_CPUID , "CPUID instruction is not supported"}, + { ERR_NO_RDTSC , "RDTSC instruction is not supported"}, + { ERR_NO_MEM , "Memory allocation failed"}, + { ERR_OPEN , "File open operation failed"}, + { ERR_BADFMT , "Bad file format"}, + { ERR_NOT_IMP , "Not implemented"}, + { ERR_CPU_UNKN , "Unsupported processor"}, + { ERR_NO_RDMSR , "RDMSR instruction is not supported"}, + { ERR_NO_DRIVER, "RDMSR driver error (generic)"}, + { ERR_NO_PERMS , "No permissions to install RDMSR driver"}, + { ERR_EXTRACT , "Cannot extract RDMSR driver (read only media?)"}, + { ERR_HANDLE , "Bad handle"}, + { ERR_INVMSR , "Invalid MSR"}, + { ERR_INVCNB , "Invalid core number"}, + { ERR_HANDLE_R , "Error on handle read"}, + { ERR_INVRANGE , "Invalid given range"}, + }; + unsigned i; + for (i = 0; i < COUNT_OF(matchtable); i++) + if (_libcpiud_errno == matchtable[i].error) + return matchtable[i].description; + return "Unknown error"; +} + + const char* cpuid_lib_version(void) { return VERSION; } + +libcpuid_warn_fn_t cpuid_set_warn_function(libcpuid_warn_fn_t new_fn) +{ + libcpuid_warn_fn_t ret = _warn_fun; + _warn_fun = new_fn; + return ret; +} + +void cpuid_set_verbosiness_level(int level) +{ + _current_verboselevel = level; +} + +cpu_vendor_t cpuid_get_vendor(void) +{ + static cpu_vendor_t vendor = VENDOR_UNKNOWN; + uint32_t raw_vendor[4]; + char vendor_str[VENDOR_STR_MAX]; + + if(vendor == VENDOR_UNKNOWN) { + if (!cpuid_present()) + set_error(ERR_NO_CPUID); + else { + cpu_exec_cpuid(0, raw_vendor); + vendor = cpuid_vendor_identify(raw_vendor, vendor_str); + } + } + return vendor; +} + +void cpuid_get_cpu_list(cpu_vendor_t vendor, struct cpu_list_t* list) +{ + switch (vendor) { + case VENDOR_INTEL: + cpuid_get_list_intel(list); + break; + case VENDOR_AMD: + cpuid_get_list_amd(list); + break; + case VENDOR_CYRIX: + make_list_from_string("Cx486,Cx5x86,6x86,6x86MX,M II,MediaGX,MediaGXi,MediaGXm", list); + break; + case VENDOR_NEXGEN: + make_list_from_string("Nx586", list); + break; + case VENDOR_TRANSMETA: + make_list_from_string("Crusoe,Efficeon", list); + break; + case VENDOR_UMC: + make_list_from_string("UMC x86 CPU", list); + break; + case VENDOR_CENTAUR: + make_list_from_string("VIA C3,VIA C7,VIA Nano", list); + break; + case VENDOR_RISE: + make_list_from_string("Rise mP6", list); + break; + case VENDOR_SIS: + make_list_from_string("SiS mP6", list); + break; + case VENDOR_NSC: + make_list_from_string("Geode GXm,Geode GXLV,Geode GX1,Geode GX2", list); + break; + default: + warnf("Unknown vendor passed to cpuid_get_cpu_list()\n"); + break; + } +} + +void cpuid_free_cpu_list(struct cpu_list_t* list) +{ + int i; + if (list->num_entries <= 0) return; + for (i = 0; i < list->num_entries; i++) + free(list->names[i]); + free(list->names); +} diff --git a/src/3rdparty/libcpuid/libcpuid.h b/src/3rdparty/libcpuid/libcpuid.h index c44990c3..f99c0fe5 100644 --- a/src/3rdparty/libcpuid/libcpuid.h +++ b/src/3rdparty/libcpuid/libcpuid.h @@ -610,6 +610,39 @@ void cpu_exec_cpuid_ext(uint32_t* regs); */ 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 @@ -635,6 +668,222 @@ int cpuid_get_raw_data(struct cpu_raw_data_t* data); */ 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:

+ * + * i) The CPU might be in some power saving state, while the OS reports its + * full-power frequency, or vice-versa.
+ * 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:
+ * + * 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.
+ * 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.
+ * 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 The return value of cpuid_get_epc(). * @details @@ -667,6 +916,230 @@ struct cpu_epc_t cpuid_get_epc(int index, const struct cpu_raw_data_t* raw); */ 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 Obtains the CPU vendor from CPUID from the current CPU + * @note The result is cached. + * @returns VENDOR_UNKNOWN if failed, otherwise the CPU vendor type. + * @see cpu_vendor_t + */ +cpu_vendor_t cpuid_get_vendor(void); + +/** + * @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); + +struct msr_driver_t; +/** + * @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* cpu_msr_driver_open(void); + +/** + * @brief Similar to \ref cpu_msr_driver_open, but accept one parameter + * + * This function works on certain operating systems (GNU/Linux, FreeBSD) + * + * @param core_num specify the core number for MSR. + * The first core number is 0. + * The last core number is \ref cpuid_get_total_cpus - 1. + * + * @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* cpu_msr_driver_open_core(unsigned core_num); + +/** + * @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, uint32_t 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_MIN_MULTIPLIER, /*!< Minimum CPU:FSB ratio for this CPU, + multiplied by 100. */ + 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, /*!< Maximum 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. */ + INFO_VOLTAGE, /*!< The current core voltage in Volt, + multiplied by 100. */ + INFO_BCLK, /*!< See \ref INFO_BUS_CLOCK. */ + INFO_BUS_CLOCK, /*!< The main bus clock in MHz, + e.g., FSB/QPI/DMI/HT base clock, + multiplied by 100. */ +} cpu_msrinfo_request_t; + +/** + * @brief Similar to \ref cpu_rdmsr, but extract a range of bits + * + * @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 highbit - the high bit in range, must be inferior to 64 + * @param lowbit - the low bit in range, must be equal or superior to 0 + * @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_range(struct msr_driver_t* handle, uint32_t msr_index, uint8_t highbit, + uint8_t lowbit, uint64_t* result); + +/** + * @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 + * @note This function is not MT-safe. If you intend to call it from multiple + * threads, guard it through a mutex or a similar primitive. + */ +int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which); +#define CPU_INVALID_VALUE 0x3fffffff + +/** + * @brief Writes the raw MSR data to a text file + * @param data - a pointer to msr_driver_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 msr_serialize_raw_data(struct msr_driver_t* handle, const char* filename); + +/** + * @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 diff --git a/src/3rdparty/libcpuid/libcpuid_types.h b/src/3rdparty/libcpuid/libcpuid_types.h index 9e897275..7854fd73 100644 --- a/src/3rdparty/libcpuid/libcpuid_types.h +++ b/src/3rdparty/libcpuid/libcpuid_types.h @@ -34,4 +34,4 @@ #include -#endif /* __LIBCPUID_TYPES_H__ */ +#endif /* __LIBCPUID_TYPES_H__ */ \ No newline at end of file diff --git a/src/3rdparty/libcpuid/libcpuid_util.c b/src/3rdparty/libcpuid/libcpuid_util.c index 440b3724..4de1871a 100644 --- a/src/3rdparty/libcpuid/libcpuid_util.c +++ b/src/3rdparty/libcpuid/libcpuid_util.c @@ -32,6 +32,8 @@ #include "libcpuid.h" #include "libcpuid_util.h" +int _current_verboselevel; + void match_features(const struct feature_map_t* matchtable, int count, uint32_t reg, struct cpu_id_t* data) { int i; @@ -40,6 +42,118 @@ void match_features(const struct feature_map_t* matchtable, int count, uint32_t data->flags[matchtable[i].feature] = 1; } +static void default_warn(const char *msg) +{ + fprintf(stderr, "%s", msg); +} + +libcpuid_warn_fn_t _warn_fun = default_warn; + +#if defined(_MSC_VER) +# define vsnprintf _vsnprintf +#endif +void warnf(const char* format, ...) +{ + char buff[1024]; + va_list va; + if (!_warn_fun) return; + va_start(va, format); + vsnprintf(buff, sizeof(buff), format, va); + va_end(va); + _warn_fun(buff); +} + +void debugf(int verboselevel, const char* format, ...) +{ + char buff[1024]; + va_list va; + if (verboselevel > _current_verboselevel) return; + va_start(va, format); + vsnprintf(buff, sizeof(buff), format, va); + va_end(va); + _warn_fun(buff); +} + +static int popcount64(uint64_t mask) +{ + int num_set_bits = 0; + + while (mask) { + mask &= mask - 1; + num_set_bits++; + } + + return num_set_bits; +} + +static int score(const struct match_entry_t* entry, const struct cpu_id_t* data, + int brand_code, uint64_t bits, int model_code) +{ + int res = 0; + if (entry->family == data->family ) res += 2; + if (entry->model == data->model ) res += 2; + if (entry->stepping == data->stepping ) res += 2; + if (entry->ext_family == data->ext_family) res += 2; + if (entry->ext_model == data->ext_model ) res += 2; + if (entry->ncores == data->num_cores ) res += 2; + if (entry->l2cache == data->l2_cache ) res += 1; + if (entry->l3cache == data->l3_cache ) res += 1; + if (entry->brand_code == brand_code ) res += 2; + if (entry->model_code == model_code ) res += 2; + + res += popcount64(entry->model_bits & bits) * 2; + return res; +} + +int match_cpu_codename(const struct match_entry_t* matchtable, int count, + struct cpu_id_t* data, int brand_code, uint64_t bits, + int model_code) +{ + int bestscore = -1; + int bestindex = 0; + int i, t; + + debugf(3, "Matching cpu f:%d, m:%d, s:%d, xf:%d, xm:%d, ncore:%d, l2:%d, bcode:%d, bits:%llu, code:%d\n", + data->family, data->model, data->stepping, data->ext_family, + data->ext_model, data->num_cores, data->l2_cache, brand_code, (unsigned long long) bits, model_code); + + for (i = 0; i < count; i++) { + t = score(&matchtable[i], data, brand_code, bits, model_code); + debugf(3, "Entry %d, `%s', score %d\n", i, matchtable[i].name, t); + if (t > bestscore) { + debugf(2, "Entry `%s' selected - best score so far (%d)\n", matchtable[i].name, t); + bestscore = t; + bestindex = i; + } + } + strcpy(data->cpu_codename, matchtable[bestindex].name); + return bestscore; +} + +void generic_get_cpu_list(const struct match_entry_t* matchtable, int count, + struct cpu_list_t* list) +{ + int i, j, n, good; + n = 0; + list->names = (char**) malloc(sizeof(char*) * count); + for (i = 0; i < count; i++) { + if (strstr(matchtable[i].name, "Unknown")) continue; + good = 1; + for (j = n - 1; j >= 0; j--) + if (!strcmp(list->names[j], matchtable[i].name)) { + good = 0; + break; + } + if (!good) continue; +#if defined(_MSC_VER) + list->names[n++] = _strdup(matchtable[i].name); +#else + list->names[n++] = strdup(matchtable[i].name); +#endif + } + list->num_entries = n; +} + static int xmatch_entry(char c, const char* p) { int i, j; @@ -91,3 +205,14 @@ int match_all(uint64_t bits, uint64_t mask) { return (bits & mask) == mask; } + +void debug_print_lbits(int debuglevel, uint64_t mask) +{ + int i, first = 0; + for (i = 0; i < 64; i++) if (mask & (((uint64_t) 1) << i)) { + if (first) first = 0; + else debugf(2, " + "); + debugf(2, "LBIT(%d)", i); + } + debugf(2, "\n"); +} diff --git a/src/3rdparty/libcpuid/libcpuid_util.h b/src/3rdparty/libcpuid/libcpuid_util.h index 0c8200e8..c3b53933 100644 --- a/src/3rdparty/libcpuid/libcpuid_util.h +++ b/src/3rdparty/libcpuid/libcpuid_util.h @@ -48,6 +48,20 @@ struct match_entry_t { int match_cpu_codename(const struct match_entry_t* matchtable, int count, struct cpu_id_t* data, int brand_code, uint64_t bits, int model_code); + +void warnf(const char* format, ...) +#ifdef __GNUC__ +__attribute__((format(printf, 1, 2))) +#endif +; +void debugf(int verboselevel, const char* format, ...) +#ifdef __GNUC__ +__attribute__((format(printf, 2, 3))) +#endif +; +void generic_get_cpu_list(const struct match_entry_t* matchtable, int count, + struct cpu_list_t* list); + /* * Seek for a pattern in `haystack'. * Pattern may be an fixed string, or contain the special metacharacters @@ -70,9 +84,15 @@ struct cpu_id_t* get_cached_cpuid(void); /* returns true if all bits of mask are present in `bits'. */ int match_all(uint64_t bits, uint64_t mask); +/* print what bits a mask consists of */ +void debug_print_lbits(int debuglevel, uint64_t mask); + /* * Sets the current errno */ int set_error(cpu_error_t err); +extern libcpuid_warn_fn_t _warn_fun; +extern int _current_verboselevel; + #endif /* __LIBCPUID_UTIL_H__ */ diff --git a/src/3rdparty/libcpuid/msrdriver.c b/src/3rdparty/libcpuid/msrdriver.c new file mode 100644 index 00000000..8f9d7ed0 --- /dev/null +++ b/src/3rdparty/libcpuid/msrdriver.c @@ -0,0 +1,593 @@ +/* + * Copyright 2009 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. + */ + +/** + * @File msrdriver.c + * @Brief Contains the binary images of the x86 and x64 MSR drivers for Windows + * @Date 2009-09-29 + * + * The driver is courtesy of Nick 'Bombera' Gabareff, and its source is actually + * available, see the contrib/ dir. + * + * However, for simplicity, here we just include the images of the compiled .SYS + * files. + * They are extracted to the filesystem on demand and loaded in the kernel + * by the cpu_msr_driver_open() function + */ +#ifdef _WIN32 +#include "asm-bits.h" +//begin { +int cc_x86driver_code_size = 4608; +uint8_t cc_x86driver_code[4608] = { + 0x4d,0x5a,0x90,0x00,0x03,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0xb8,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x00,0x00,0x00,0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd, + 0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68,0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d, + 0x20,0x63,0x61,0x6e,0x6e,0x6f,0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20, + 0x44,0x4f,0x53,0x20,0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x9f,0x99,0x48,0xdf,0xdb,0xf8,0x26,0x8c,0xdb,0xf8,0x26,0x8c,0xdb,0xf8,0x26,0x8c, + 0xdb,0xf8,0x27,0x8c,0xdd,0xf8,0x26,0x8c,0x21,0xdb,0x3f,0x8c,0xd8,0xf8,0x26,0x8c,0xfc,0x3e, + 0x57,0x8c,0xda,0xf8,0x26,0x8c,0xfc,0x3e,0x5a,0x8c,0xda,0xf8,0x26,0x8c,0xfc,0x3e,0x5e,0x8c, + 0xda,0xf8,0x26,0x8c,0x52,0x69,0x63,0x68,0xdb,0xf8,0x26,0x8c,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x50,0x45,0x00,0x00,0x4c,0x01,0x07,0x00,0x12,0x9b,0x9b,0x4a,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0xe0,0x00,0x02,0x21,0x0b,0x01,0x08,0x00,0x00,0x06,0x00,0x00,0x00,0x0a, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x20,0x00,0x00, + 0x00,0x00,0x01,0x00,0x00,0x10,0x00,0x00,0x00,0x02,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x04,0x00,0x00, + 0xa9,0xd1,0x00,0x00,0x01,0x00,0x00,0x04,0x00,0x00,0x10,0x00,0x00,0x10,0x00,0x00,0x00,0x00, + 0x10,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x60,0x00,0x00,0xc0,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x70,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x20,0x00,0x00,0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x2e,0x74, + 0x65,0x78,0x74,0x00,0x00,0x00,0xa3,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x02,0x00,0x00, + 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00, + 0x00,0x68,0x2e,0x72,0x64,0x61,0x74,0x61,0x00,0x00,0x62,0x00,0x00,0x00,0x00,0x20,0x00,0x00, + 0x00,0x02,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x40,0x00,0x00,0x48,0x2e,0x64,0x61,0x74,0x61,0x00,0x00,0x00,0x04,0x00,0x00,0x00, + 0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0xc8,0x50,0x41,0x47,0x45,0x30,0x44,0x45,0x46, + 0x8c,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x60,0x49,0x4e,0x49,0x54, + 0x00,0x00,0x00,0x00,0xd4,0x00,0x00,0x00,0x00,0x50,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0a, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0xe2, + 0x2e,0x72,0x73,0x72,0x63,0x00,0x00,0x00,0xc0,0x03,0x00,0x00,0x00,0x60,0x00,0x00,0x00,0x04, + 0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x40,0x00,0x00,0x42,0x2e,0x72,0x65,0x6c,0x6f,0x63,0x00,0x00,0x68,0x00,0x00,0x00,0x00,0x70, + 0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x8b,0x4c, + 0x24,0x08,0x83,0x61,0x18,0x00,0x83,0x61,0x1c,0x00,0x32,0xd2,0xff,0x15,0x08,0x20,0x01,0x00, + 0x33,0xc0,0xc2,0x08,0x00,0x56,0x8b,0x74,0x24,0x0c,0x8b,0x46,0x60,0x81,0x78,0x0c,0x0c,0xe0, + 0x22,0x00,0x57,0x75,0x3c,0x83,0x78,0x04,0x08,0x72,0x36,0x83,0x78,0x08,0x04,0x75,0x07,0x8b, + 0x46,0x0c,0x8b,0x08,0xeb,0x05,0xb9,0x9c,0x01,0x00,0x00,0x8b,0x7e,0x0c,0x0f,0x32,0x89,0x07, + 0x89,0x57,0x04,0xc7,0x46,0x1c,0x08,0x00,0x00,0x00,0x33,0xff,0x32,0xd2,0x8b,0xce,0xff,0x15, + 0x08,0x20,0x01,0x00,0x8b,0xc7,0x5f,0x5e,0xc2,0x08,0x00,0x83,0x66,0x1c,0x00,0xbf,0x01,0x00, + 0x00,0xc0,0x89,0x7e,0x18,0xeb,0xe1,0x55,0x8b,0xec,0x51,0x51,0x8b,0x45,0x08,0xff,0x70,0x04, + 0xff,0x15,0x04,0x20,0x01,0x00,0x68,0x3c,0x20,0x01,0x00,0x8d,0x45,0xf8,0x50,0xff,0x15,0x00, + 0x20,0x01,0x00,0x8d,0x45,0xf8,0x50,0xff,0x15,0x14,0x20,0x01,0x00,0xc9,0xc2,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x5c,0x50,0x00,0x00,0x74,0x50,0x00,0x00,0x86,0x50,0x00,0x00, + 0x9c,0x50,0x00,0x00,0xb4,0x50,0x00,0x00,0x44,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x5c,0x00, + 0x44,0x00,0x65,0x00,0x76,0x00,0x69,0x00,0x63,0x00,0x65,0x00,0x5c,0x00,0x54,0x00,0x6d,0x00, + 0x70,0x00,0x52,0x00,0x64,0x00,0x72,0x00,0x00,0x00,0x00,0x00,0x5c,0x00,0x44,0x00,0x6f,0x00, + 0x73,0x00,0x44,0x00,0x65,0x00,0x76,0x00,0x69,0x00,0x63,0x00,0x65,0x00,0x73,0x00,0x5c,0x00, + 0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00,0x64,0x00,0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x55,0x8b,0xec,0x83, + 0xec,0x14,0x56,0x8b,0x35,0x00,0x20,0x01,0x00,0x57,0x68,0x1c,0x20,0x01,0x00,0x8d,0x45,0xf4, + 0x50,0xff,0xd6,0x8b,0x7d,0x08,0x8d,0x45,0xfc,0x50,0x6a,0x00,0x6a,0x00,0x6a,0x22,0x8d,0x45, + 0xf4,0x50,0x6a,0x04,0x57,0xff,0x15,0x10,0x20,0x01,0x00,0x85,0xc0,0x75,0x4f,0x68,0x3c,0x20, + 0x01,0x00,0x8d,0x45,0xec,0x50,0xff,0xd6,0x8d,0x45,0xf4,0x50,0x8d,0x45,0xec,0x50,0xff,0x15, + 0x0c,0x20,0x01,0x00,0x8b,0xf0,0x85,0xf6,0x74,0x0d,0xff,0x75,0xfc,0xff,0x15,0x04,0x20,0x01, + 0x00,0x8b,0xc6,0xeb,0x23,0x8b,0x45,0xfc,0xa3,0x00,0x30,0x01,0x00,0xb8,0x00,0x10,0x01,0x00, + 0x89,0x47,0x38,0x89,0x47,0x40,0xc7,0x47,0x34,0x75,0x10,0x01,0x00,0xc7,0x47,0x70,0x19,0x10, + 0x01,0x00,0x33,0xc0,0x5f,0x5e,0xc9,0xc2,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x28,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc6,0x50, + 0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x5c,0x50,0x00,0x00,0x74,0x50,0x00,0x00,0x86,0x50, + 0x00,0x00,0x9c,0x50,0x00,0x00,0xb4,0x50,0x00,0x00,0x44,0x50,0x00,0x00,0x00,0x00,0x00,0x00, + 0x4b,0x01,0x49,0x6f,0x44,0x65,0x6c,0x65,0x74,0x65,0x53,0x79,0x6d,0x62,0x6f,0x6c,0x69,0x63, + 0x4c,0x69,0x6e,0x6b,0x00,0x00,0x0b,0x04,0x52,0x74,0x6c,0x49,0x6e,0x69,0x74,0x55,0x6e,0x69, + 0x63,0x6f,0x64,0x65,0x53,0x74,0x72,0x69,0x6e,0x67,0x00,0x00,0x49,0x01,0x49,0x6f,0x44,0x65, + 0x6c,0x65,0x74,0x65,0x44,0x65,0x76,0x69,0x63,0x65,0x00,0x00,0xda,0x01,0x49,0x6f,0x66,0x43, + 0x6f,0x6d,0x70,0x6c,0x65,0x74,0x65,0x52,0x65,0x71,0x75,0x65,0x73,0x74,0x00,0x00,0x41,0x01, + 0x49,0x6f,0x43,0x72,0x65,0x61,0x74,0x65,0x53,0x79,0x6d,0x62,0x6f,0x6c,0x69,0x63,0x4c,0x69, + 0x6e,0x6b,0x00,0x00,0x38,0x01,0x49,0x6f,0x43,0x72,0x65,0x61,0x74,0x65,0x44,0x65,0x76,0x69, + 0x63,0x65,0x00,0x00,0x6e,0x74,0x6f,0x73,0x6b,0x72,0x6e,0x6c,0x2e,0x65,0x78,0x65,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x10,0x00,0x00,0x00,0x18,0x00,0x00,0x80, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00, + 0x00,0x00,0x30,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x01,0x00,0x09,0x04,0x00,0x00,0x48,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x5c,0x03, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x5c,0x03,0x34,0x00,0x00,0x00,0x56,0x00,0x53,0x00,0x5f,0x00,0x56,0x00,0x45,0x00,0x52,0x00, + 0x53,0x00,0x49,0x00,0x4f,0x00,0x4e,0x00,0x5f,0x00,0x49,0x00,0x4e,0x00,0x46,0x00,0x4f,0x00, + 0x00,0x00,0x00,0x00,0xbd,0x04,0xef,0xfe,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x04,0x00,0x04,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xba,0x02,0x00,0x00,0x01,0x00,0x53,0x00,0x74,0x00,0x72,0x00,0x69,0x00,0x6e,0x00, + 0x67,0x00,0x46,0x00,0x69,0x00,0x6c,0x00,0x65,0x00,0x49,0x00,0x6e,0x00,0x66,0x00,0x6f,0x00, + 0x00,0x00,0x96,0x02,0x00,0x00,0x01,0x00,0x30,0x00,0x34,0x00,0x30,0x00,0x39,0x00,0x30,0x00, + 0x34,0x00,0x62,0x00,0x30,0x00,0x00,0x00,0x58,0x00,0x20,0x00,0x01,0x00,0x43,0x00,0x6f,0x00, + 0x6d,0x00,0x6d,0x00,0x65,0x00,0x6e,0x00,0x74,0x00,0x73,0x00,0x00,0x00,0x4d,0x00,0x53,0x00, + 0x52,0x00,0x20,0x00,0x72,0x00,0x65,0x00,0x61,0x00,0x64,0x00,0x65,0x00,0x72,0x00,0x20,0x00, + 0x33,0x00,0x32,0x00,0x2d,0x00,0x62,0x00,0x69,0x00,0x74,0x00,0x20,0x00,0x6b,0x00,0x65,0x00, + 0x72,0x00,0x6e,0x00,0x65,0x00,0x6c,0x00,0x20,0x00,0x64,0x00,0x72,0x00,0x69,0x00,0x76,0x00, + 0x65,0x00,0x72,0x00,0x00,0x00,0x42,0x00,0x11,0x00,0x01,0x00,0x43,0x00,0x6f,0x00,0x6d,0x00, + 0x70,0x00,0x61,0x00,0x6e,0x00,0x79,0x00,0x4e,0x00,0x61,0x00,0x6d,0x00,0x65,0x00,0x00,0x00, + 0x00,0x00,0x49,0x00,0x72,0x00,0x6f,0x00,0x6e,0x00,0x20,0x00,0x53,0x00,0x74,0x00,0x65,0x00, + 0x65,0x00,0x64,0x00,0x73,0x00,0x20,0x00,0x49,0x00,0x6e,0x00,0x63,0x00,0x2e,0x00,0x00,0x00, + 0x00,0x00,0x60,0x00,0x1c,0x00,0x01,0x00,0x46,0x00,0x69,0x00,0x6c,0x00,0x65,0x00,0x44,0x00, + 0x65,0x00,0x73,0x00,0x63,0x00,0x72,0x00,0x69,0x00,0x70,0x00,0x74,0x00,0x69,0x00,0x6f,0x00, + 0x6e,0x00,0x00,0x00,0x00,0x00,0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00,0x64,0x00,0x72,0x00, + 0x20,0x00,0x33,0x00,0x32,0x00,0x2d,0x00,0x62,0x00,0x69,0x00,0x74,0x00,0x20,0x00,0x4b,0x00, + 0x65,0x00,0x72,0x00,0x6e,0x00,0x65,0x00,0x6c,0x00,0x20,0x00,0x4d,0x00,0x6f,0x00,0x64,0x00, + 0x75,0x00,0x6c,0x00,0x65,0x00,0x00,0x00,0x36,0x00,0x0b,0x00,0x01,0x00,0x46,0x00,0x69,0x00, + 0x6c,0x00,0x65,0x00,0x56,0x00,0x65,0x00,0x72,0x00,0x73,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00, + 0x00,0x00,0x00,0x00,0x31,0x00,0x2c,0x00,0x20,0x00,0x30,0x00,0x2c,0x00,0x20,0x00,0x30,0x00, + 0x2c,0x00,0x20,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x2e,0x00,0x07,0x00,0x01,0x00,0x49,0x00, + 0x6e,0x00,0x74,0x00,0x65,0x00,0x72,0x00,0x6e,0x00,0x61,0x00,0x6c,0x00,0x4e,0x00,0x61,0x00, + 0x6d,0x00,0x65,0x00,0x00,0x00,0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00,0x64,0x00,0x72,0x00, + 0x00,0x00,0x00,0x00,0x4a,0x00,0x13,0x00,0x01,0x00,0x4c,0x00,0x65,0x00,0x67,0x00,0x61,0x00, + 0x6c,0x00,0x43,0x00,0x6f,0x00,0x70,0x00,0x79,0x00,0x72,0x00,0x69,0x00,0x67,0x00,0x68,0x00, + 0x74,0x00,0x00,0x00,0x4e,0x00,0x69,0x00,0x63,0x00,0x6b,0x00,0x20,0x00,0x47,0x00,0x61,0x00, + 0x62,0x00,0x61,0x00,0x72,0x00,0x65,0x00,0x76,0x00,0x20,0x00,0x27,0x00,0x32,0x00,0x30,0x00, + 0x30,0x00,0x39,0x00,0x00,0x00,0x00,0x00,0x3e,0x00,0x0b,0x00,0x01,0x00,0x4f,0x00,0x72,0x00, + 0x69,0x00,0x67,0x00,0x69,0x00,0x6e,0x00,0x61,0x00,0x6c,0x00,0x46,0x00,0x69,0x00,0x6c,0x00, + 0x65,0x00,0x6e,0x00,0x61,0x00,0x6d,0x00,0x65,0x00,0x00,0x00,0x54,0x00,0x6d,0x00,0x70,0x00, + 0x52,0x00,0x64,0x00,0x72,0x00,0x2e,0x00,0x73,0x00,0x79,0x00,0x73,0x00,0x00,0x00,0x00,0x00, + 0x54,0x00,0x1a,0x00,0x01,0x00,0x50,0x00,0x72,0x00,0x6f,0x00,0x64,0x00,0x75,0x00,0x63,0x00, + 0x74,0x00,0x4e,0x00,0x61,0x00,0x6d,0x00,0x65,0x00,0x00,0x00,0x00,0x00,0x43,0x00,0x6f,0x00, + 0x72,0x00,0x65,0x00,0x20,0x00,0x32,0x00,0x20,0x00,0x54,0x00,0x65,0x00,0x6d,0x00,0x70,0x00, + 0x65,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x75,0x00,0x72,0x00,0x65,0x00,0x20,0x00,0x52,0x00, + 0x65,0x00,0x61,0x00,0x64,0x00,0x65,0x00,0x72,0x00,0x00,0x00,0x3a,0x00,0x0b,0x00,0x01,0x00, + 0x50,0x00,0x72,0x00,0x6f,0x00,0x64,0x00,0x75,0x00,0x63,0x00,0x74,0x00,0x56,0x00,0x65,0x00, + 0x72,0x00,0x73,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x00,0x00,0x31,0x00,0x2c,0x00,0x20,0x00, + 0x30,0x00,0x2c,0x00,0x20,0x00,0x30,0x00,0x2c,0x00,0x20,0x00,0x31,0x00,0x00,0x00,0x00,0x00, + 0x44,0x00,0x00,0x00,0x01,0x00,0x56,0x00,0x61,0x00,0x72,0x00,0x46,0x00,0x69,0x00,0x6c,0x00, + 0x65,0x00,0x49,0x00,0x6e,0x00,0x66,0x00,0x6f,0x00,0x00,0x00,0x00,0x00,0x24,0x00,0x04,0x00, + 0x00,0x00,0x54,0x00,0x72,0x00,0x61,0x00,0x6e,0x00,0x73,0x00,0x6c,0x00,0x61,0x00,0x74,0x00, + 0x69,0x00,0x6f,0x00,0x6e,0x00,0x00,0x00,0x00,0x00,0x09,0x04,0xb0,0x04,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x14,0x00,0x00,0x00, + 0x10,0x30,0x5c,0x30,0x82,0x30,0x87,0x30,0x91,0x30,0x9b,0x30,0x00,0x40,0x00,0x00,0x1c,0x00, + 0x00,0x00,0x09,0x30,0x0f,0x30,0x2f,0x30,0x38,0x30,0x4c,0x30,0x5b,0x30,0x67,0x30,0x6c,0x30, + 0x79,0x30,0x80,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; +int cc_x64driver_code_size = 5120; +uint8_t cc_x64driver_code[5120] = { + 0x4d,0x5a,0x90,0x00,0x03,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xff,0xff,0x00,0x00,0xb8,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xd0,0x00,0x00,0x00,0x0e,0x1f,0xba,0x0e,0x00,0xb4,0x09,0xcd, + 0x21,0xb8,0x01,0x4c,0xcd,0x21,0x54,0x68,0x69,0x73,0x20,0x70,0x72,0x6f,0x67,0x72,0x61,0x6d, + 0x20,0x63,0x61,0x6e,0x6e,0x6f,0x74,0x20,0x62,0x65,0x20,0x72,0x75,0x6e,0x20,0x69,0x6e,0x20, + 0x44,0x4f,0x53,0x20,0x6d,0x6f,0x64,0x65,0x2e,0x0d,0x0d,0x0a,0x24,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0xb7,0x04,0xa8,0xc2,0xf3,0x65,0xc6,0x91,0xf3,0x65,0xc6,0x91,0xf3,0x65,0xc6,0x91, + 0xf3,0x65,0xc7,0x91,0xf4,0x65,0xc6,0x91,0x85,0xf8,0xbd,0x91,0xf0,0x65,0xc6,0x91,0x85,0xf8, + 0xab,0x91,0xf0,0x65,0xc6,0x91,0x30,0x6a,0x98,0x91,0xf2,0x65,0xc6,0x91,0x85,0xf8,0xbe,0x91, + 0xf2,0x65,0xc6,0x91,0x52,0x69,0x63,0x68,0xf3,0x65,0xc6,0x91,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x45,0x00,0x00,0x64,0x86,0x07,0x00, + 0x41,0xc8,0x6d,0x49,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x00,0x22,0x00,0x0b,0x02, + 0x08,0x00,0x00,0x06,0x00,0x00,0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x60,0x00,0x00, + 0x00,0x10,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x02, + 0x00,0x00,0x05,0x00,0x02,0x00,0x05,0x00,0x02,0x00,0x05,0x00,0x02,0x00,0x00,0x00,0x00,0x00, + 0x00,0x80,0x00,0x00,0x00,0x04,0x00,0x00,0x79,0x44,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00, + 0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6c,0x60,0x00,0x00,0x28,0x00,0x00,0x00, + 0x00,0x70,0x00,0x00,0xc0,0x03,0x00,0x00,0x00,0x40,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x20,0x00,0x00, + 0x1c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x2e,0x74,0x65,0x78,0x74,0x00,0x00,0x00,0x26,0x01,0x00,0x00,0x00,0x10, + 0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x68,0x2e,0x72,0x64,0x61,0x74,0x61,0x00,0x00,0xf0,0x00, + 0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x48,0x2e,0x64,0x61,0x74,0x61,0x00, + 0x00,0x00,0x18,0x01,0x00,0x00,0x00,0x30,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x08,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0xc8,0x2e,0x70, + 0x64,0x61,0x74,0x61,0x00,0x00,0x48,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x00,0x02,0x00,0x00, + 0x00,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00, + 0x00,0x48,0x50,0x41,0x47,0x45,0x30,0x44,0x45,0x46,0x4e,0x01,0x00,0x00,0x00,0x50,0x00,0x00, + 0x00,0x02,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x20,0x00,0x00,0x60,0x49,0x4e,0x49,0x54,0x00,0x00,0x00,0x00,0x60,0x01,0x00,0x00, + 0x00,0x60,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x0e,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0xe2,0x2e,0x72,0x73,0x72,0x63,0x00,0x00,0x00, + 0xc0,0x03,0x00,0x00,0x00,0x70,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x10,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00,0x42,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x83,0xec,0x28, + 0x33,0xc9,0x48,0x8b,0xc2,0x89,0x4a,0x30,0x48,0x89,0x4a,0x38,0x33,0xd2,0x48,0x8b,0xc8,0xff, + 0x15,0xfd,0x0f,0x00,0x00,0x33,0xc0,0x48,0x83,0xc4,0x28,0xc3,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x48,0x83,0xec,0x28,0x48,0x8b,0x82,0xb8,0x00,0x00, + 0x00,0x4c,0x8b,0xca,0x81,0x78,0x18,0x0c,0xe0,0x22,0x00,0x75,0x43,0x83,0x78,0x08,0x08,0x72, + 0x3d,0x83,0x78,0x10,0x04,0x75,0x08,0x48,0x8b,0x42,0x18,0x8b,0x08,0xeb,0x05,0xb9,0x9c,0x01, + 0x00,0x00,0x4c,0x8b,0x42,0x18,0x0f,0x32,0x48,0xc1,0xe2,0x20,0x49,0x8b,0xc9,0x48,0x0b,0xc2, + 0x33,0xd2,0x49,0x89,0x00,0x49,0xc7,0x41,0x38,0x08,0x00,0x00,0x00,0xff,0x15,0x95,0x0f,0x00, + 0x00,0x33,0xc0,0x48,0x83,0xc4,0x28,0xc3,0xc7,0x42,0x30,0x01,0x00,0x00,0xc0,0x48,0xc7,0x42, + 0x38,0x00,0x00,0x00,0x00,0x49,0x8b,0xc9,0x33,0xd2,0xff,0x15,0x74,0x0f,0x00,0x00,0xb8,0x01, + 0x00,0x00,0xc0,0x48,0x83,0xc4,0x28,0xc3,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc, + 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x48,0x83,0xec,0x38,0x48,0x8b,0x49,0x08,0xff,0x15, + 0x32,0x0f,0x00,0x00,0x48,0x8d,0x15,0x1b,0x00,0x00,0x00,0x48,0x8d,0x4c,0x24,0x20,0xff,0x15, + 0x18,0x0f,0x00,0x00,0x48,0x8d,0x4c,0x24,0x20,0xff,0x15,0x05,0x0f,0x00,0x00,0x48,0x83,0xc4, + 0x38,0xc3,0x5c,0x00,0x44,0x00,0x6f,0x00,0x73,0x00,0x44,0x00,0x65,0x00,0x76,0x00,0x69,0x00, + 0x63,0x00,0x65,0x00,0x73,0x00,0x5c,0x00,0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00,0x64,0x00, + 0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0xe6,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0x60,0x00,0x00, + 0x00,0x00,0x00,0x00,0x16,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x61,0x00,0x00,0x00,0x00, + 0x00,0x00,0x40,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0xd0,0x60,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x41,0xc8,0x6d,0x49,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x49,0x00,0x00,0x00, + 0x5c,0x20,0x00,0x00,0x5c,0x06,0x00,0x00,0x52,0x53,0x44,0x53,0xd9,0x5e,0xab,0x47,0xc4,0xf2, + 0x4f,0x40,0xaa,0xe9,0x90,0x47,0x67,0x30,0xa5,0xfa,0x03,0x00,0x00,0x00,0x44,0x3a,0x5c,0x74, + 0x6d,0x70,0x5c,0x4b,0x65,0x72,0x6e,0x65,0x6c,0x5c,0x6f,0x62,0x6a,0x66,0x72,0x65,0x5f,0x77, + 0x6e,0x65,0x74,0x5f,0x41,0x4d,0x44,0x36,0x34,0x5c,0x61,0x6d,0x64,0x36,0x34,0x5c,0x54,0x6d, + 0x70,0x52,0x64,0x72,0x2e,0x70,0x64,0x62,0x00,0x00,0x00,0x00,0x01,0x04,0x01,0x00,0x04,0x42, + 0x00,0x00,0x01,0x04,0x01,0x00,0x04,0x42,0x00,0x00,0x01,0x04,0x01,0x00,0x04,0x62,0x00,0x00, + 0x21,0x00,0x00,0x00,0x10,0x50,0x00,0x00,0x74,0x50,0x00,0x00,0xe4,0x20,0x00,0x00,0x21,0x08, + 0x02,0x00,0x08,0x74,0x13,0x00,0x10,0x50,0x00,0x00,0x74,0x50,0x00,0x00,0xe4,0x20,0x00,0x00, + 0x01,0x0c,0x03,0x00,0x0c,0x34,0x12,0x00,0x04,0xe2,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xcd,0x5d,0x20,0xd2,0x66,0xd4,0xff,0xff,0x32,0xa2,0xdf,0x2d,0x99,0x2b,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x10,0x10,0x00,0x00,0x32,0x10,0x00,0x00,0xa8,0x20,0x00,0x00,0x40,0x10, + 0x00,0x00,0xbe,0x10,0x00,0x00,0xb0,0x20,0x00,0x00,0xd0,0x10,0x00,0x00,0x00,0x11,0x00,0x00, + 0xb8,0x20,0x00,0x00,0x10,0x50,0x00,0x00,0x74,0x50,0x00,0x00,0xe4,0x20,0x00,0x00,0x74,0x50, + 0x00,0x00,0xe8,0x50,0x00,0x00,0xd0,0x20,0x00,0x00,0xe8,0x50,0x00,0x00,0xf5,0x50,0x00,0x00, + 0xc0,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x48,0x83,0xec,0x78,0x48,0x89,0x9c,0x24, + 0x90,0x00,0x00,0x00,0x48,0x8b,0xd9,0x48,0x8d,0x15,0x0a,0x01,0x00,0x00,0x48,0x8d,0x4c,0x24, + 0x48,0xff,0x15,0xd7,0xcf,0xff,0xff,0x41,0xb9,0x22,0x00,0x00,0x00,0x4c,0x8d,0x5c,0x24,0x40, + 0x4c,0x89,0x5c,0x24,0x30,0x4c,0x8d,0x44,0x24,0x48,0x41,0x8d,0x51,0xe6,0x48,0x8b,0xcb,0xc6, + 0x44,0x24,0x28,0x00,0xc7,0x44,0x24,0x20,0x00,0x00,0x00,0x00,0xff,0x15,0xc0,0xcf,0xff,0xff, + 0x85,0xc0,0x0f,0x85,0x80,0x00,0x00,0x00,0x48,0x8d,0x15,0x91,0x00,0x00,0x00,0x48,0x8d,0x4c, + 0x24,0x58,0x48,0x89,0xbc,0x24,0x98,0x00,0x00,0x00,0xff,0x15,0x86,0xcf,0xff,0xff,0x48,0x8d, + 0x54,0x24,0x48,0x48,0x8d,0x4c,0x24,0x58,0xff,0x15,0x86,0xcf,0xff,0xff,0x85,0xc0,0x8b,0xf8, + 0x74,0x0f,0x48,0x8b,0x4c,0x24,0x40,0xff,0x15,0x6d,0xcf,0xff,0xff,0x8b,0xc7,0xeb,0x39,0x48, + 0x8b,0x44,0x24,0x40,0x48,0x89,0x05,0x5d,0xe0,0xff,0xff,0x48,0x8d,0x05,0x16,0xc0,0xff,0xff, + 0x48,0x89,0x43,0x68,0x48,0x8d,0x05,0x4b,0xbf,0xff,0xff,0x48,0x89,0x43,0x70,0x48,0x89,0x83, + 0x80,0x00,0x00,0x00,0x48,0x8d,0x05,0x69,0xbf,0xff,0xff,0x48,0x89,0x83,0xe0,0x00,0x00,0x00, + 0x33,0xc0,0x48,0x8b,0xbc,0x24,0x98,0x00,0x00,0x00,0x48,0x8b,0x9c,0x24,0x90,0x00,0x00,0x00, + 0x48,0x83,0xc4,0x78,0xc3,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x5c,0x00, + 0x44,0x00,0x6f,0x00,0x73,0x00,0x44,0x00,0x65,0x00,0x76,0x00,0x69,0x00,0x63,0x00,0x65,0x00, + 0x73,0x00,0x5c,0x00,0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00,0x64,0x00,0x72,0x00,0x00,0x00, + 0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x5c,0x00,0x44,0x00,0x65,0x00,0x76,0x00, + 0x69,0x00,0x63,0x00,0x65,0x00,0x5c,0x00,0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00,0x64,0x00, + 0x72,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x48,0x8b,0x05,0xf1,0xd0,0xff,0xff,0x49,0xb9,0x32,0xa2,0xdf,0x2d,0x99,0x2b,0x00,0x00,0x48, + 0x85,0xc0,0x74,0x05,0x49,0x3b,0xc1,0x75,0x2f,0x4c,0x8d,0x05,0xd6,0xd0,0xff,0xff,0x48,0xb8, + 0x20,0x03,0x00,0x00,0x80,0xf7,0xff,0xff,0x48,0x8b,0x00,0x49,0x33,0xc0,0x49,0xb8,0xff,0xff, + 0xff,0xff,0xff,0xff,0x00,0x00,0x49,0x23,0xc0,0x49,0x0f,0x44,0xc1,0x48,0x89,0x05,0xae,0xd0, + 0xff,0xff,0x48,0xf7,0xd0,0x48,0x89,0x05,0x9c,0xd0,0xff,0xff,0xe9,0xa7,0xef,0xff,0xff,0xcc, + 0xcc,0xcc,0x98,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x61,0x00,0x00, + 0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe6,0x60,0x00,0x00,0x00,0x00,0x00,0x00, + 0xfe,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x16,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x61, + 0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x61,0x00,0x00,0x00,0x00,0x00,0x00,0xd0,0x60,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xf6,0x01,0x49,0x6f,0x66,0x43, + 0x6f,0x6d,0x70,0x6c,0x65,0x74,0x65,0x52,0x65,0x71,0x75,0x65,0x73,0x74,0x00,0x00,0x61,0x01, + 0x49,0x6f,0x44,0x65,0x6c,0x65,0x74,0x65,0x53,0x79,0x6d,0x62,0x6f,0x6c,0x69,0x63,0x4c,0x69, + 0x6e,0x6b,0x00,0x00,0x3e,0x04,0x52,0x74,0x6c,0x49,0x6e,0x69,0x74,0x55,0x6e,0x69,0x63,0x6f, + 0x64,0x65,0x53,0x74,0x72,0x69,0x6e,0x67,0x00,0x00,0x5f,0x01,0x49,0x6f,0x44,0x65,0x6c,0x65, + 0x74,0x65,0x44,0x65,0x76,0x69,0x63,0x65,0x00,0x00,0x55,0x01,0x49,0x6f,0x43,0x72,0x65,0x61, + 0x74,0x65,0x53,0x79,0x6d,0x62,0x6f,0x6c,0x69,0x63,0x4c,0x69,0x6e,0x6b,0x00,0x00,0x4c,0x01, + 0x49,0x6f,0x43,0x72,0x65,0x61,0x74,0x65,0x44,0x65,0x76,0x69,0x63,0x65,0x00,0x00,0x6e,0x74, + 0x6f,0x73,0x6b,0x72,0x6e,0x6c,0x2e,0x65,0x78,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x10,0x00,0x00,0x00,0x18,0x00,0x00,0x80,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00, + 0x30,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x00,0x09,0x04,0x00,0x00,0x48,0x00,0x00,0x00,0x60,0x70,0x00,0x00,0x60,0x03,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x03, + 0x34,0x00,0x00,0x00,0x56,0x00,0x53,0x00,0x5f,0x00,0x56,0x00,0x45,0x00,0x52,0x00,0x53,0x00, + 0x49,0x00,0x4f,0x00,0x4e,0x00,0x5f,0x00,0x49,0x00,0x4e,0x00,0x46,0x00,0x4f,0x00,0x00,0x00, + 0x00,0x00,0xbd,0x04,0xef,0xfe,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x17,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00, + 0x04,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0xbe,0x02,0x00,0x00,0x01,0x00,0x53,0x00,0x74,0x00,0x72,0x00,0x69,0x00,0x6e,0x00,0x67,0x00, + 0x46,0x00,0x69,0x00,0x6c,0x00,0x65,0x00,0x49,0x00,0x6e,0x00,0x66,0x00,0x6f,0x00,0x00,0x00, + 0x9a,0x02,0x00,0x00,0x01,0x00,0x30,0x00,0x34,0x00,0x30,0x00,0x39,0x00,0x30,0x00,0x34,0x00, + 0x62,0x00,0x30,0x00,0x00,0x00,0x58,0x00,0x20,0x00,0x01,0x00,0x43,0x00,0x6f,0x00,0x6d,0x00, + 0x6d,0x00,0x65,0x00,0x6e,0x00,0x74,0x00,0x73,0x00,0x00,0x00,0x4d,0x00,0x53,0x00,0x52,0x00, + 0x20,0x00,0x72,0x00,0x65,0x00,0x61,0x00,0x64,0x00,0x65,0x00,0x72,0x00,0x20,0x00,0x36,0x00, + 0x34,0x00,0x2d,0x00,0x62,0x00,0x69,0x00,0x74,0x00,0x20,0x00,0x6b,0x00,0x65,0x00,0x72,0x00, + 0x6e,0x00,0x65,0x00,0x6c,0x00,0x20,0x00,0x64,0x00,0x72,0x00,0x69,0x00,0x76,0x00,0x65,0x00, + 0x72,0x00,0x00,0x00,0x42,0x00,0x11,0x00,0x01,0x00,0x43,0x00,0x6f,0x00,0x6d,0x00,0x70,0x00, + 0x61,0x00,0x6e,0x00,0x79,0x00,0x4e,0x00,0x61,0x00,0x6d,0x00,0x65,0x00,0x00,0x00,0x00,0x00, + 0x49,0x00,0x72,0x00,0x6f,0x00,0x6e,0x00,0x20,0x00,0x53,0x00,0x74,0x00,0x65,0x00,0x65,0x00, + 0x64,0x00,0x73,0x00,0x20,0x00,0x49,0x00,0x6e,0x00,0x63,0x00,0x2e,0x00,0x00,0x00,0x00,0x00, + 0x60,0x00,0x1c,0x00,0x01,0x00,0x46,0x00,0x69,0x00,0x6c,0x00,0x65,0x00,0x44,0x00,0x65,0x00, + 0x73,0x00,0x63,0x00,0x72,0x00,0x69,0x00,0x70,0x00,0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00, + 0x00,0x00,0x00,0x00,0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00,0x64,0x00,0x72,0x00,0x20,0x00, + 0x36,0x00,0x34,0x00,0x2d,0x00,0x62,0x00,0x69,0x00,0x74,0x00,0x20,0x00,0x4b,0x00,0x65,0x00, + 0x72,0x00,0x6e,0x00,0x65,0x00,0x6c,0x00,0x20,0x00,0x4d,0x00,0x6f,0x00,0x64,0x00,0x75,0x00, + 0x6c,0x00,0x65,0x00,0x00,0x00,0x36,0x00,0x0b,0x00,0x01,0x00,0x46,0x00,0x69,0x00,0x6c,0x00, + 0x65,0x00,0x56,0x00,0x65,0x00,0x72,0x00,0x73,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x00,0x00, + 0x00,0x00,0x31,0x00,0x2c,0x00,0x20,0x00,0x30,0x00,0x2c,0x00,0x20,0x00,0x30,0x00,0x2c,0x00, + 0x20,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x2e,0x00,0x07,0x00,0x01,0x00,0x49,0x00,0x6e,0x00, + 0x74,0x00,0x65,0x00,0x72,0x00,0x6e,0x00,0x61,0x00,0x6c,0x00,0x4e,0x00,0x61,0x00,0x6d,0x00, + 0x65,0x00,0x00,0x00,0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00,0x64,0x00,0x72,0x00,0x00,0x00, + 0x00,0x00,0x4a,0x00,0x13,0x00,0x01,0x00,0x4c,0x00,0x65,0x00,0x67,0x00,0x61,0x00,0x6c,0x00, + 0x43,0x00,0x6f,0x00,0x70,0x00,0x79,0x00,0x72,0x00,0x69,0x00,0x67,0x00,0x68,0x00,0x74,0x00, + 0x00,0x00,0x4e,0x00,0x69,0x00,0x63,0x00,0x6b,0x00,0x20,0x00,0x47,0x00,0x61,0x00,0x62,0x00, + 0x61,0x00,0x72,0x00,0x65,0x00,0x76,0x00,0x20,0x00,0x27,0x00,0x32,0x00,0x30,0x00,0x30,0x00, + 0x39,0x00,0x00,0x00,0x00,0x00,0x42,0x00,0x0d,0x00,0x01,0x00,0x4f,0x00,0x72,0x00,0x69,0x00, + 0x67,0x00,0x69,0x00,0x6e,0x00,0x61,0x00,0x6c,0x00,0x46,0x00,0x69,0x00,0x6c,0x00,0x65,0x00, + 0x6e,0x00,0x61,0x00,0x6d,0x00,0x65,0x00,0x00,0x00,0x54,0x00,0x6d,0x00,0x70,0x00,0x52,0x00, + 0x64,0x00,0x72,0x00,0x36,0x00,0x34,0x00,0x2e,0x00,0x73,0x00,0x79,0x00,0x73,0x00,0x00,0x00, + 0x00,0x00,0x54,0x00,0x1a,0x00,0x01,0x00,0x50,0x00,0x72,0x00,0x6f,0x00,0x64,0x00,0x75,0x00, + 0x63,0x00,0x74,0x00,0x4e,0x00,0x61,0x00,0x6d,0x00,0x65,0x00,0x00,0x00,0x00,0x00,0x43,0x00, + 0x6f,0x00,0x72,0x00,0x65,0x00,0x20,0x00,0x32,0x00,0x20,0x00,0x54,0x00,0x65,0x00,0x6d,0x00, + 0x70,0x00,0x65,0x00,0x72,0x00,0x61,0x00,0x74,0x00,0x75,0x00,0x72,0x00,0x65,0x00,0x20,0x00, + 0x52,0x00,0x65,0x00,0x61,0x00,0x64,0x00,0x65,0x00,0x72,0x00,0x00,0x00,0x3a,0x00,0x0b,0x00, + 0x01,0x00,0x50,0x00,0x72,0x00,0x6f,0x00,0x64,0x00,0x75,0x00,0x63,0x00,0x74,0x00,0x56,0x00, + 0x65,0x00,0x72,0x00,0x73,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x00,0x00,0x31,0x00,0x2c,0x00, + 0x20,0x00,0x30,0x00,0x2c,0x00,0x20,0x00,0x30,0x00,0x2c,0x00,0x20,0x00,0x31,0x00,0x00,0x00, + 0x00,0x00,0x44,0x00,0x00,0x00,0x01,0x00,0x56,0x00,0x61,0x00,0x72,0x00,0x46,0x00,0x69,0x00, + 0x6c,0x00,0x65,0x00,0x49,0x00,0x6e,0x00,0x66,0x00,0x6f,0x00,0x00,0x00,0x00,0x00,0x24,0x00, + 0x04,0x00,0x00,0x00,0x54,0x00,0x72,0x00,0x61,0x00,0x6e,0x00,0x73,0x00,0x6c,0x00,0x61,0x00, + 0x74,0x00,0x69,0x00,0x6f,0x00,0x6e,0x00,0x00,0x00,0x00,0x00,0x09,0x04,0xb0,0x04,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +}; +//} end +#endif // _WIN32 + +int msrdriver_dummy; // a dummy to avoid a linker warning on OS X. diff --git a/src/3rdparty/libcpuid/rdmsr.c b/src/3rdparty/libcpuid/rdmsr.c new file mode 100644 index 00000000..afcccccd --- /dev/null +++ b/src/3rdparty/libcpuid/rdmsr.c @@ -0,0 +1,1054 @@ +/* + * Copyright 2009 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. + */ +#define _XOPEN_SOURCE 500 +#include +#include +#include +#include "libcpuid.h" +#include "asm-bits.h" +#include "libcpuid_util.h" +#include "libcpuid_internal.h" +#include "rdtsc.h" + +#if defined (__linux__) || defined (__gnu_linux__) +/* Assuming linux with /dev/cpu/x/msr: */ +#include +#include +#include +#include +#include +#include +struct msr_driver_t { int fd; }; +static int rdmsr_supported(void); +static int load_driver(char *msr_path) +{ + const int file_exists = !access(msr_path, F_OK); + const int file_readable = !access(msr_path, R_OK); + + if (file_exists && file_readable) + return 1; + else if (file_exists && !file_readable) + return 0; + else if (getuid() != 0) + return 0; + else + return !system("modprobe msr 2> /dev/null"); +} + +struct msr_driver_t* cpu_msr_driver_open(void) +{ + return cpu_msr_driver_open_core(0); +} + +struct msr_driver_t* cpu_msr_driver_open_core(unsigned core_num) +{ + char msr[32]; + struct msr_driver_t* handle; + if (core_num >= cpuid_get_total_cpus()) { + set_error(ERR_INVCNB); + return NULL; + } + if (!rdmsr_supported()) { + set_error(ERR_NO_RDMSR); + return NULL; + } + sprintf(msr, "/dev/cpu/%u/msr", core_num); + if(!load_driver(msr)) { + set_error(ERR_NO_DRIVER); + return NULL; + } + int fd = open(msr, O_RDONLY); + if (fd < 0) { + if (errno == EIO) { + set_error(ERR_NO_RDMSR); + return NULL; + } + set_error(ERR_NO_DRIVER); + return NULL; + } + handle = (struct msr_driver_t*) malloc(sizeof(struct msr_driver_t)); + handle->fd = fd; + return handle; +} + +int cpu_rdmsr(struct msr_driver_t* driver, uint32_t msr_index, uint64_t* result) +{ + ssize_t ret; + + if (!driver || driver->fd < 0) + return set_error(ERR_HANDLE); + ret = pread(driver->fd, result, 8, msr_index); + if (ret != 8) + return set_error(ERR_INVMSR); + return 0; +} + +int cpu_msr_driver_close(struct msr_driver_t* drv) +{ + if (drv && drv->fd >= 0) { + close(drv->fd); + free(drv); + } + return 0; +} + +/* #endif defined (__linux__) || defined (__gnu_linux__) */ + +#elif defined (__FreeBSD__) || defined (__DragonFly__) +/* Assuming FreeBSD with /dev/cpuctlX */ +#include +#include +#include +#include +#include + +struct msr_driver_t { int fd; }; +static int rdmsr_supported(void); +static int load_driver(char *msr_path) +{ + const int file_exists = !access(msr_path, F_OK); + const int file_readable = !access(msr_path, R_OK); + + if (file_exists && file_readable) + return 1; + else if (file_exists && !file_readable) + return 0; + else if (getuid() != 0) + return 0; + else + return !system("kldload -n cpuctl 2> /dev/null"); +} + +struct msr_driver_t* cpu_msr_driver_open(void) +{ + return cpu_msr_driver_open_core(0); +} + +struct msr_driver_t* cpu_msr_driver_open_core(unsigned core_num) +{ + char msr[32]; + struct msr_driver_t* handle; + if (core_num >= cpuid_get_total_cpus()) { + set_error(ERR_INVCNB); + return NULL; + } + if (!rdmsr_supported()) { + set_error(ERR_NO_RDMSR); + return NULL; + } + sprintf(msr, "/dev/cpuctl%u", core_num); + if(!load_driver(msr)) { + set_error(ERR_NO_DRIVER); + return NULL; + } + int fd = open(msr, O_RDONLY); + if (fd < 0) { + if (errno == EIO) { + set_error(ERR_NO_RDMSR); + return NULL; + } + set_error(ERR_NO_DRIVER); + return NULL; + } + handle = (struct msr_driver_t*) malloc(sizeof(struct msr_driver_t)); + handle->fd = fd; + return handle; +} + +int cpu_rdmsr(struct msr_driver_t* driver, uint32_t msr_index, uint64_t* result) +{ + cpuctl_msr_args_t args; + args.msr = msr_index; + + if (!driver || driver->fd < 0) + return set_error(ERR_HANDLE); + + if(ioctl(driver->fd, CPUCTL_RDMSR, &args)) + return set_error(ERR_INVMSR); + + *result = args.data; + return 0; +} + +int cpu_msr_driver_close(struct msr_driver_t* drv) +{ + if (drv && drv->fd >= 0) { + close(drv->fd); + free(drv); + } + return 0; +} + +/* #endif defined (__FreeBSD__) || defined (__DragonFly__) */ + +#elif defined (_WIN32) +#include +#include +#include + +extern uint8_t cc_x86driver_code[]; +extern int cc_x86driver_code_size; +extern uint8_t cc_x64driver_code[]; +extern int cc_x64driver_code_size; + +struct msr_driver_t { + char driver_path[MAX_PATH + 1]; + SC_HANDLE scManager; + volatile SC_HANDLE scDriver; + HANDLE hhDriver; + OVERLAPPED ovl; + int errorcode; +}; + +static int rdmsr_supported(void); +static int extract_driver(struct msr_driver_t* driver); +static int load_driver(struct msr_driver_t* driver); + +struct msr_driver_t* cpu_msr_driver_open(void) +{ + struct msr_driver_t* drv; + int status; + if (!rdmsr_supported()) { + set_error(ERR_NO_RDMSR); + return NULL; + } + + drv = (struct msr_driver_t*) malloc(sizeof(struct msr_driver_t)); + if (!drv) { + set_error(ERR_NO_MEM); + return NULL; + } + memset(drv, 0, sizeof(struct msr_driver_t)); + + if (!extract_driver(drv)) { + free(drv); + set_error(ERR_EXTRACT); + return NULL; + } + + status = load_driver(drv); + if (!DeleteFile(drv->driver_path)) + debugf(1, "Deleting temporary driver file failed.\n"); + if (!status) { + set_error(drv->errorcode ? drv->errorcode : ERR_NO_DRIVER); + free(drv); + return NULL; + } + return drv; +} + +struct msr_driver_t* cpu_msr_driver_open_core(unsigned core_num) +{ + warnf("cpu_msr_driver_open_core(): parameter ignored (function is the same as cpu_msr_driver_open)\n"); + return cpu_msr_driver_open(); +} + +typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); +static BOOL is_running_x64(void) +{ + BOOL bIsWow64 = FALSE; + + LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(__TEXT("kernel32")), "IsWow64Process"); + if(NULL != fnIsWow64Process) + fnIsWow64Process(GetCurrentProcess(), &bIsWow64); + return bIsWow64; +} + + +static int extract_driver(struct msr_driver_t* driver) +{ + FILE *f; + if (!GetTempPath(sizeof(driver->driver_path), driver->driver_path)) return 0; + strcat(driver->driver_path, "TmpRdr.sys"); + + f = fopen(driver->driver_path, "wb"); + if (!f) return 0; + if (is_running_x64()) + fwrite(cc_x64driver_code, 1, cc_x64driver_code_size, f); + else + fwrite(cc_x86driver_code, 1, cc_x86driver_code_size, f); + fclose(f); + return 1; +} + +static BOOL wait_for_service_state(SC_HANDLE hService, DWORD dwDesiredState, SERVICE_STATUS *lpsrvStatus){ + BOOL fOK = FALSE; + DWORD dwWaitHint; + + if(hService != NULL){ + while(TRUE){ + fOK = QueryServiceStatus(hService, lpsrvStatus); + if(!fOK) + break; + if(lpsrvStatus->dwCurrentState == dwDesiredState) + break; + + dwWaitHint = lpsrvStatus->dwWaitHint / 10; // Poll 1/10 of the wait hint + if (dwWaitHint < 1000) + dwWaitHint = 1000; // At most once per second + if (dwWaitHint > 10000) + dwWaitHint = 10000; // At least every 10 seconds + Sleep(dwWaitHint); + } + } + + return fOK; +} + +static int load_driver(struct msr_driver_t* drv) +{ + LPTSTR lpszInfo = __TEXT("RDMSR Executor Driver"); + USHORT uLen = 0; + SERVICE_STATUS srvStatus = {0}; + BOOL fRunning = FALSE; + DWORD dwLastError; + LPTSTR lpszDriverServiceName = __TEXT("TmpRdr"); + TCHAR lpszDriverName[] = __TEXT("\\\\.\\Global\\TmpRdr"); + + if((LPVOID)(drv->scManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) != NULL) { + drv->scDriver = CreateService(drv->scManager, lpszDriverServiceName, lpszInfo, SERVICE_ALL_ACCESS, + SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, + drv->driver_path, NULL, NULL, NULL, NULL, NULL); + if(drv->scDriver == NULL){ + switch(dwLastError = GetLastError()){ + case ERROR_SERVICE_EXISTS: + case ERROR_SERVICE_MARKED_FOR_DELETE:{ + LPQUERY_SERVICE_CONFIG lpqsc; + DWORD dwBytesNeeded; + + drv->scDriver = OpenService(drv->scManager, lpszDriverServiceName, SERVICE_ALL_ACCESS); + if(drv->scDriver == NULL){ + debugf(1, "Error opening service: %d\n", GetLastError()); + break; + } + + QueryServiceConfig(drv->scDriver, NULL, 0, &dwBytesNeeded); + if((dwLastError = GetLastError()) == ERROR_INSUFFICIENT_BUFFER){ + lpqsc = calloc(1, dwBytesNeeded); + if(!QueryServiceConfig(drv->scDriver, lpqsc, dwBytesNeeded, &dwBytesNeeded)){ + free(lpqsc); + debugf(1, "Error query service config(adjusted buffer): %d\n", GetLastError()); + goto clean_up; + } + else{ + free(lpqsc); + } + } + else{ + debugf(1, "Error query service config: %d\n", dwLastError); + goto clean_up; + } + + break; + } + case ERROR_ACCESS_DENIED: + drv->errorcode = ERR_NO_PERMS; + break; + default: + debugf(1, "Create driver service failed: %d\n", dwLastError); + break; + } + } + if(drv->scDriver != NULL){ + if(StartService(drv->scDriver, 0, NULL)){ + if(!wait_for_service_state(drv->scDriver, SERVICE_RUNNING, &srvStatus)){ + debugf(1, "Driver load failed.\n"); + DeleteService(drv->scDriver); + CloseServiceHandle(drv->scManager); + drv->scDriver = NULL; + goto clean_up; + } else { + fRunning = TRUE; + } + } else{ + if((dwLastError = GetLastError()) == ERROR_SERVICE_ALREADY_RUNNING) + fRunning = TRUE; + else{ + debugf(1, "Driver start failed.\n"); + DeleteService(drv->scDriver); + CloseServiceHandle(drv->scManager); + drv->scDriver = NULL; + goto clean_up; + } + + } + if(fRunning) + debugf(1, "Driver already running.\n"); + else + debugf(1, "Driver loaded.\n"); + CloseServiceHandle(drv->scManager); + drv->hhDriver = CreateFile(lpszDriverName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); + drv->ovl.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + return 1; + } + } else { + debugf(1, "Open SCM failed: %d\n", GetLastError()); + } + +clean_up: + if(drv->scManager != NULL){ + CloseServiceHandle(drv->scManager); + drv->scManager = 0; // pointless + } + if(drv->scDriver != NULL){ + if(!DeleteService(drv->scDriver)) + debugf(1, "Delete driver service failed: %d\n", GetLastError()); + CloseServiceHandle(drv->scDriver); + drv->scDriver = 0; + } + + return 0; +} + +#define FILE_DEVICE_UNKNOWN 0x00000022 +#define IOCTL_UNKNOWN_BASE FILE_DEVICE_UNKNOWN +#define IOCTL_PROCVIEW_RDMSR CTL_CODE(IOCTL_UNKNOWN_BASE, 0x0803, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +int cpu_rdmsr(struct msr_driver_t* driver, uint32_t msr_index, uint64_t* result) +{ + DWORD dwBytesReturned; + __int64 msrdata; + SERVICE_STATUS srvStatus = {0}; + + if (!driver) + return set_error(ERR_HANDLE); + DeviceIoControl(driver->hhDriver, IOCTL_PROCVIEW_RDMSR, &msr_index, sizeof(int), &msrdata, sizeof(__int64), &dwBytesReturned, &driver->ovl); + GetOverlappedResult(driver->hhDriver, &driver->ovl, &dwBytesReturned, TRUE); + *result = msrdata; + return 0; +} + +int cpu_msr_driver_close(struct msr_driver_t* drv) +{ + SERVICE_STATUS srvStatus = {0}; + if (drv == NULL) return 0; + if(drv->scDriver != NULL){ + if (drv->hhDriver) CancelIo(drv->hhDriver); + if(drv->ovl.hEvent != NULL) + CloseHandle(drv->ovl.hEvent); + if (drv->hhDriver) CloseHandle(drv->hhDriver); + drv->hhDriver = NULL; + drv->ovl.hEvent = NULL; + if (ControlService(drv->scDriver, SERVICE_CONTROL_STOP, &srvStatus)){ + if (wait_for_service_state(drv->scDriver, SERVICE_STOPPED, &srvStatus)){ + DeleteService(drv->scDriver); + } + } + } + return 0; +} + +/* endif defined (_WIN32) */ + +#else /* Unsupported OS */ +/* On others OS (i.e., Darwin), we still do not support RDMSR, so supply dummy struct + and functions */ + +#define RDMSR_UNSUPPORTED_OS + +struct msr_driver_t { int dummy; }; +struct msr_driver_t* cpu_msr_driver_open(void) +{ + set_error(ERR_NOT_IMP); + return NULL; +} + +struct msr_driver_t* cpu_msr_driver_open_core(unsigned core_num) +{ + set_error(ERR_NOT_IMP); + return NULL; +} + +int cpu_rdmsr(struct msr_driver_t* driver, uint32_t msr_index, uint64_t* result) +{ + return set_error(ERR_NOT_IMP); +} + +int cpu_msr_driver_close(struct msr_driver_t* driver) +{ + return set_error(ERR_NOT_IMP); +} + +int cpu_rdmsr_range(struct msr_driver_t* handle, uint32_t msr_index, uint8_t highbit, + uint8_t lowbit, uint64_t* result) +{ + return set_error(ERR_NOT_IMP); +} + +int cpu_msrinfo(struct msr_driver_t* driver, cpu_msrinfo_request_t which) +{ + return set_error(ERR_NOT_IMP); +} + +int msr_serialize_raw_data(struct msr_driver_t* handle, const char* filename) +{ + return set_error(ERR_NOT_IMP); +} + +#endif /* Unsupported OS */ + +#ifndef RDMSR_UNSUPPORTED_OS + +/* Useful links for hackers: +- AMD MSRs: + AMD BIOS and Kernel Developer’s Guide (BKDG) + * AMD Family 10h Processors + http://support.amd.com/TechDocs/31116.pdf + * AMD Family 11h Processors + http://support.amd.com/TechDocs/41256.pdf + * AMD Family 12h Processors + http://support.amd.com/TechDocs/41131.pdf + * AMD Family 14h Processors + http://support.amd.com/TechDocs/43170_14h_Mod_00h-0Fh_BKDG.pdf + * AMD Family 15h Processors + http://support.amd.com/TechDocs/42301_15h_Mod_00h-0Fh_BKDG.pdf + http://support.amd.com/TechDocs/42300_15h_Mod_10h-1Fh_BKDG.pdf + http://support.amd.com/TechDocs/49125_15h_Models_30h-3Fh_BKDG.pdf + http://support.amd.com/TechDocs/50742_15h_Models_60h-6Fh_BKDG.pdf + http://support.amd.com/TechDocs/55072_AMD_Family_15h_Models_70h-7Fh_BKDG.pdf + * AMD Family 16h Processors + http://support.amd.com/TechDocs/48751_16h_bkdg.pdf + http://support.amd.com/TechDocs/52740_16h_Models_30h-3Fh_BKDG.pdf + + AMD Processor Programming Reference (PPR) + * AMD Family 17h Processors + https://support.amd.com/TechDocs/54945_PPR_Family_17h_Models_00h-0Fh.pdf + +- Intel MSRs: + Intel® 64 and IA-32 Architectures Software Developer’s Manual + * Volume 3 (3A, 3B, 3C & 3D): System Programming Guide + http://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-system-programming-manual-325384.pdf +*/ + +/* AMD MSRs addresses */ +#define MSR_PSTATE_L 0xC0010061 +#define MSR_PSTATE_S 0xC0010063 +#define MSR_PSTATE_0 0xC0010064 +#define MSR_PSTATE_1 0xC0010065 +#define MSR_PSTATE_2 0xC0010066 +#define MSR_PSTATE_3 0xC0010067 +#define MSR_PSTATE_4 0xC0010068 +#define MSR_PSTATE_5 0xC0010069 +#define MSR_PSTATE_6 0xC001006A +#define MSR_PSTATE_7 0xC001006B +static const uint32_t amd_msr[] = { + MSR_PSTATE_L, + MSR_PSTATE_S, + MSR_PSTATE_0, + MSR_PSTATE_1, + MSR_PSTATE_2, + MSR_PSTATE_3, + MSR_PSTATE_4, + MSR_PSTATE_5, + MSR_PSTATE_6, + MSR_PSTATE_7, + CPU_INVALID_VALUE +}; + +/* Intel MSRs addresses */ +#define IA32_MPERF 0xE7 +#define IA32_APERF 0xE8 +#define IA32_PERF_STATUS 0x198 +#define IA32_THERM_STATUS 0x19C +#define MSR_EBL_CR_POWERON 0x2A +#define MSR_TURBO_RATIO_LIMIT 0x1AD +#define MSR_TEMPERATURE_TARGET 0x1A2 +#define MSR_PERF_STATUS 0x198 +#define MSR_PLATFORM_INFO 0xCE +static const uint32_t intel_msr[] = { + IA32_MPERF, + IA32_APERF, + IA32_PERF_STATUS, + IA32_THERM_STATUS, + MSR_EBL_CR_POWERON, + MSR_TURBO_RATIO_LIMIT, + MSR_TEMPERATURE_TARGET, + MSR_PERF_STATUS, + MSR_PLATFORM_INFO, + CPU_INVALID_VALUE +}; + +struct msr_info_t { + int cpu_clock; + struct msr_driver_t *handle; + struct cpu_id_t *id; + struct internal_id_info_t *internal; +}; + +static int rdmsr_supported(void) +{ + struct cpu_id_t* id = get_cached_cpuid(); + return id->flags[CPU_FEATURE_MSR]; +} + +static int perfmsr_measure(struct msr_driver_t* handle, int msr) +{ + int err; + uint64_t a, b; + uint64_t x, y; + err = cpu_rdmsr(handle, msr, &x); + if (err) return CPU_INVALID_VALUE; + sys_precise_clock(&a); + busy_loop_delay(10); + cpu_rdmsr(handle, msr, &y); + sys_precise_clock(&b); + if (a >= b || x > y) return CPU_INVALID_VALUE; + return (int) ((y - x) / (b - a)); +} + +static int get_amd_multipliers(struct msr_info_t *info, uint32_t pstate, double *multiplier) +{ + int i, err; + uint64_t CpuFid, CpuDid, CpuDidLSD; + + /* Constant values needed for 12h family */ + const struct { uint64_t did; double divisor; } divisor_t[] = { + { 0x0, 1 }, + { 0x1, 1.5 }, + { 0x2, 2 }, + { 0x3, 3 }, + { 0x4, 4 }, + { 0x5, 6 }, + { 0x6, 8 }, + { 0x7, 12 }, + { 0x8, 16 }, + }; + const int num_dids = (int) COUNT_OF(divisor_t); + + /* Constant values for common families */ + const int magic_constant = (info->id->ext_family == 0x11) ? 0x8 : 0x10; + const int is_apu = ((FUSION_C <= info->internal->code.amd) && (info->internal->code.amd <= FUSION_A)) || (info->internal->bits & _APU_); + const double divisor = is_apu ? 1.0 : 2.0; + + /* Check if P-state is valid */ + if (pstate < MSR_PSTATE_0 || MSR_PSTATE_7 < pstate) + return 1; + + switch (info->id->ext_family) { + case 0x12: + /* BKDG 12h, page 469 + MSRC001_00[6B:64][8:4] is CpuFid + MSRC001_00[6B:64][3:0] is CpuDid + CPU COF is (100MHz * (CpuFid + 10h) / (divisor specified by CpuDid)) + Note: This family contains only APUs */ + err = cpu_rdmsr_range(info->handle, pstate, 8, 4, &CpuFid); + err += cpu_rdmsr_range(info->handle, pstate, 3, 0, &CpuDid); + i = 0; + while (i < num_dids && divisor_t[i].did != CpuDid) + i++; + if (i < num_dids) + *multiplier = (double) ((CpuFid + magic_constant) / divisor_t[i].divisor); + else + err++; + break; + case 0x14: + /* BKDG 14h, page 430 + MSRC001_00[6B:64][8:4] is CpuDidMSD + MSRC001_00[6B:64][3:0] is CpuDidLSD + PLL COF is (100 MHz * (D18F3xD4[MainPllOpFreqId] + 10h)) + Divisor is (CpuDidMSD + (CpuDidLSD * 0.25) + 1) + CPU COF is (main PLL frequency specified by D18F3xD4[MainPllOpFreqId]) / (core clock divisor specified by CpuDidMSD and CpuDidLSD) + Note: This family contains only APUs */ + err = cpu_rdmsr_range(info->handle, pstate, 8, 4, &CpuDid); + err += cpu_rdmsr_range(info->handle, pstate, 3, 0, &CpuDidLSD); + *multiplier = (double) (((info->cpu_clock + 5) / 100 + magic_constant) / (CpuDid + CpuDidLSD * 0.25 + 1)); + break; + case 0x10: + /* BKDG 10h, page 429 + MSRC001_00[6B:64][8:6] is CpuDid + MSRC001_00[6B:64][5:0] is CpuFid + CPU COF is (100 MHz * (CpuFid + 10h) / (2^CpuDid)) + Note: This family contains only CPUs */ + case 0x11: + /* BKDG 11h, page 236 + MSRC001_00[6B:64][8:6] is CpuDid + MSRC001_00[6B:64][5:0] is CpuFid + CPU COF is ((100 MHz * (CpuFid + 08h)) / (2^CpuDid)) + Note: This family contains only CPUs */ + case 0x15: + /* BKDG 15h, page 570/580/635/692 (00h-0Fh/10h-1Fh/30h-3Fh/60h-6Fh) + MSRC001_00[6B:64][8:6] is CpuDid + MSRC001_00[6B:64][5:0] is CpuFid + CoreCOF is (100 * (MSRC001_00[6B:64][CpuFid] + 10h) / (2^MSRC001_00[6B:64][CpuDid])) + Note: This family contains BOTH CPUs and APUs */ + case 0x16: + /* BKDG 16h, page 549/611 (00h-0Fh/30h-3Fh) + MSRC001_00[6B:64][8:6] is CpuDid + MSRC001_00[6B:64][5:0] is CpuFid + CoreCOF is (100 * (MSRC001_00[6B:64][CpuFid] + 10h) / (2^MSRC001_00[6B:64][CpuDid])) + Note: This family contains only APUs */ + err = cpu_rdmsr_range(info->handle, pstate, 8, 6, &CpuDid); + err += cpu_rdmsr_range(info->handle, pstate, 5, 0, &CpuFid); + *multiplier = (double) ((CpuFid + magic_constant) / (1ull << CpuDid)) / divisor; + break; + case 0x17: + /* PPR 17h, pages 30 and 138-139 + MSRC001_00[6B:64][13:8] is CpuDfsId + MSRC001_00[6B:64][7:0] is CpuFid + CoreCOF is (Core::X86::Msr::PStateDef[CpuFid[7:0]] / Core::X86::Msr::PStateDef[CpuDfsId]) * 200 */ + err = cpu_rdmsr_range(info->handle, pstate, 13, 8, &CpuDid); + err += cpu_rdmsr_range(info->handle, pstate, 7, 0, &CpuFid); + *multiplier = (double) (CpuFid / CpuDid) * 2; + break; + default: + err = 1; + break; + } + + return err; +} + +static uint32_t get_amd_last_pstate_addr(struct msr_info_t *info) +{ + static uint32_t last_addr = 0x0; + uint64_t reg = 0x0; + + /* The result is cached, need to be computed once */ + if(last_addr != 0x0) + return last_addr; + + /* Refer links above + MSRC001_00[6B:64][63] is PstateEn + PstateEn indicates if the rest of the P-state information in the register is valid after a reset */ + last_addr = MSR_PSTATE_7 + 1; + while((reg == 0x0) && (last_addr > MSR_PSTATE_0)) { + last_addr--; + cpu_rdmsr_range(info->handle, last_addr, 63, 63, ®); + } + return last_addr; +} + +static double get_info_min_multiplier(struct msr_info_t *info) +{ + int err; + double mult; + uint32_t addr; + uint64_t reg; + + if(info->id->vendor == VENDOR_INTEL) { + /* Refer links above + Table 35-12. MSRs in Next Generation Intel Atom Processors Based on the Goldmont Microarchitecture + Table 35-13. MSRs in Processors Based on Intel® Microarchitecture Code Name Nehalem + Table 35-18. MSRs Supported by Intel® Processors based on Intel® microarchitecture code name Sandy Bridge (Contd.) + Table 35-23. Additional MSRs Supported by 3rd Generation Intel® Coreâ„¢ Processors (based on Intel® microarchitecture code name Ivy Bridge) + Table 35-24. MSRs Supported by Intel® Xeon® Processors E5 v2 Product Family (based on Ivy Bridge-E microarchitecture) + Table 35-27. Additional MSRs Supported by Processors based on the Haswell or Haswell-E microarchitectures + Table 35-34. Additional MSRs Common to Intel® Xeon® Processor D and Intel Xeon Processors E5 v4 Family Based on the Broadwell Microarchitecture + Table 35-40. Selected MSRs Supported by Next Generation Intel® Xeon Phiâ„¢ Processors with DisplayFamily_DisplayModel Signature 06_57H + MSR_PLATFORM_INFO[47:40] is Maximum Efficiency Ratio + Maximum Efficiency Ratio is the minimum ratio that the processor can operates */ + err = cpu_rdmsr_range(info->handle, MSR_PLATFORM_INFO, 47, 40, ®); + if (!err) return (double) reg; + } + else if(info->id->vendor == VENDOR_AMD) { + /* N.B.: Find the last P-state + get_amd_last_pstate_addr() returns the last P-state, MSR_PSTATE_0 <= addr <= MSR_PSTATE_7 */ + addr = get_amd_last_pstate_addr(info); + err = get_amd_multipliers(info, addr, &mult); + if (!err) return mult; + } + + return (double) CPU_INVALID_VALUE / 100; +} + +static double get_info_cur_multiplier(struct msr_info_t *info) +{ + int err; + double mult; + uint64_t reg; + + if(info->id->vendor == VENDOR_INTEL && info->internal->code.intel == PENTIUM) { + err = cpu_rdmsr(info->handle, MSR_EBL_CR_POWERON, ®); + if (!err) return (double) ((reg>>22) & 0x1f); + } + else if(info->id->vendor == VENDOR_INTEL && info->internal->code.intel != PENTIUM) { + /* Refer links above + Table 35-2. IA-32 Architectural MSRs (Contd.) + IA32_PERF_STATUS[15:0] is Current performance State Value + [7:0] is 0x0, [15:8] looks like current ratio */ + err = cpu_rdmsr_range(info->handle, IA32_PERF_STATUS, 15, 8, ®); + if (!err) return (double) reg; + } + else if(info->id->vendor == VENDOR_AMD) { + /* Refer links above + MSRC001_0063[2:0] is CurPstate */ + err = cpu_rdmsr_range(info->handle, MSR_PSTATE_S, 2, 0, ®); + err += get_amd_multipliers(info, MSR_PSTATE_0 + (uint32_t) reg, &mult); + if (!err) return mult; + } + + return (double) CPU_INVALID_VALUE / 100; +} + +static double get_info_max_multiplier(struct msr_info_t *info) +{ + int err; + double mult; + uint64_t reg; + + if(info->id->vendor == VENDOR_INTEL && info->internal->code.intel == PENTIUM) { + err = cpu_rdmsr(info->handle, IA32_PERF_STATUS, ®); + if (!err) return (double) ((reg >> 40) & 0x1f); + } + else if(info->id->vendor == VENDOR_INTEL && info->internal->code.intel != PENTIUM) { + /* Refer links above + Table 35-10. Specific MSRs Supported by Intel® Atomâ„¢ Processor C2000 Series with CPUID Signature 06_4DH + Table 35-12. MSRs in Next Generation Intel Atom Processors Based on the Goldmont Microarchitecture (Contd.) + Table 35-13. MSRs in Processors Based on Intel® Microarchitecture Code Name Nehalem (Contd.) + Table 35-14. Additional MSRs in Intel® Xeon® Processor 5500 and 3400 Series + Table 35-16. Additional MSRs Supported by Intel Processors (Based on Intel® Microarchitecture Code Name Westmere) + Table 35-19. MSRs Supported by 2nd Generation Intel® Coreâ„¢ Processors (Intel® microarchitecture code name Sandy Bridge) + Table 35-21. Selected MSRs Supported by Intel® Xeon® Processors E5 Family (based on Sandy Bridge microarchitecture) + Table 35-28. MSRs Supported by 4th Generation Intel® Coreâ„¢ Processors (Haswell microarchitecture) (Contd.) + Table 35-30. Additional MSRs Supported by Intel® Xeon® Processor E5 v3 Family + Table 35-33. Additional MSRs Supported by Intel® Coreâ„¢ M Processors and 5th Generation Intel® Coreâ„¢ Processors + Table 35-34. Additional MSRs Common to Intel® Xeon® Processor D and Intel Xeon Processors E5 v4 Family Based on the Broadwell Microarchitecture + Table 35-37. Additional MSRs Supported by 6th Generation Intel® Coreâ„¢ Processors Based on Skylake Microarchitecture + Table 35-40. Selected MSRs Supported by Next Generation Intel® Xeon Phiâ„¢ Processors with DisplayFamily_DisplayModel Signature 06_57H + MSR_TURBO_RATIO_LIMIT[7:0] is Maximum Ratio Limit for 1C */ + err = cpu_rdmsr_range(info->handle, MSR_TURBO_RATIO_LIMIT, 7, 0, ®); + if (!err) return (double) reg; + } + else if(info->id->vendor == VENDOR_AMD) { + /* Refer links above + MSRC001_0064 is Pb0 + Pb0 is the highest-performance boosted P-state */ + err = get_amd_multipliers(info, MSR_PSTATE_0, &mult); + if (!err) return mult; + } + + return (double) CPU_INVALID_VALUE / 100; +} + +static int get_info_temperature(struct msr_info_t *info) +{ + int err; + uint64_t DigitalReadout, ReadingValid, TemperatureTarget; + + if(info->id->vendor == VENDOR_INTEL) { + /* Refer links above + Table 35-2. IA-32 Architectural MSRs + IA32_THERM_STATUS[22:16] is Digital Readout + IA32_THERM_STATUS[31] is Reading Valid + + Table 35-6. MSRs Common to the Silvermont Microarchitecture and Newer Microarchitectures for Intel® Atom + Table 35-13. MSRs in Processors Based on Intel® Microarchitecture Code Name Nehalem (Contd.) + Table 35-18. MSRs Supported by Intel® Processors based on Intel® microarchitecture code name Sandy Bridge (Contd.) + Table 35-24. MSRs Supported by Intel® Xeon® Processors E5 v2 Product Family (based on Ivy Bridge-E microarchitecture) (Contd.) + Table 35-34. Additional MSRs Common to Intel® Xeon® Processor D and Intel Xeon Processors E5 v4 Family Based on the Broadwell Microarchitecture + Table 35-40. Selected MSRs Supported by Next Generation Intel® Xeon Phiâ„¢ Processors with DisplayFamily_DisplayModel Signature 06_57H + MSR_TEMPERATURE_TARGET[23:16] is Temperature Target */ + err = cpu_rdmsr_range(info->handle, IA32_THERM_STATUS, 22, 16, &DigitalReadout); + err += cpu_rdmsr_range(info->handle, IA32_THERM_STATUS, 31, 31, &ReadingValid); + err += cpu_rdmsr_range(info->handle, MSR_TEMPERATURE_TARGET, 23, 16, &TemperatureTarget); + if(!err && ReadingValid) return (int) (TemperatureTarget - DigitalReadout); + } + + return CPU_INVALID_VALUE; +} + +static double get_info_voltage(struct msr_info_t *info) +{ + int err; + double VIDStep; + uint64_t reg, CpuVid; + + if(info->id->vendor == VENDOR_INTEL) { + /* Refer links above + Table 35-18. MSRs Supported by Intel® Processors based on Intel® microarchitecture code name Sandy Bridge (Contd.) + MSR_PERF_STATUS[47:32] is Core Voltage + P-state core voltage can be computed by MSR_PERF_STATUS[37:32] * (float) 1/(2^13). */ + err = cpu_rdmsr_range(info->handle, MSR_PERF_STATUS, 47, 32, ®); + if (!err) return (double) reg / (1 << 13); + } + else if(info->id->vendor == VENDOR_AMD) { + /* Refer links above + MSRC001_00[6B:64][15:9] is CpuVid (Jaguar and before) + MSRC001_00[6B:64][21:14] is CpuVid (Zen) + MSRC001_0063[2:0] is P-state Status + BKDG 10h, page 49: voltage = 1.550V - 0.0125V * SviVid (SVI1) + BKDG 15h, page 50: Voltage = 1.5500 - 0.00625 * Vid[7:0] (SVI2) + SVI2 since Piledriver (Family 15h, 2nd-gen): Models 10h-1Fh Processors */ + VIDStep = ((info->id->ext_family < 0x15) || ((info->id->ext_family == 0x15) && (info->id->ext_model < 0x10))) ? 0.0125 : 0.00625; + err = cpu_rdmsr_range(info->handle, MSR_PSTATE_S, 2, 0, ®); + if(info->id->ext_family < 0x17) + err += cpu_rdmsr_range(info->handle, MSR_PSTATE_0 + (uint32_t) reg, 15, 9, &CpuVid); + else + err += cpu_rdmsr_range(info->handle, MSR_PSTATE_0 + (uint32_t) reg, 21, 14, &CpuVid); + if (!err && MSR_PSTATE_0 + (uint32_t) reg <= MSR_PSTATE_7) return 1.550 - VIDStep * CpuVid; + } + + return (double) CPU_INVALID_VALUE / 100; +} + +static double get_info_bus_clock(struct msr_info_t *info) +{ + int err; + double mult; + uint32_t addr; + uint64_t reg; + + if(info->id->vendor == VENDOR_INTEL) { + /* Refer links above + Table 35-12. MSRs in Next Generation Intel Atom Processors Based on the Goldmont Microarchitecture + Table 35-13. MSRs in Processors Based on Intel® Microarchitecture Code Name Nehalem + Table 35-18. MSRs Supported by Intel® Processors based on Intel® microarchitecture code name Sandy Bridge (Contd.) + Table 35-23. Additional MSRs Supported by 3rd Generation Intel® Coreâ„¢ Processors (based on Intel® microarchitecture code name Ivy Bridge) + Table 35-24. MSRs Supported by Intel® Xeon® Processors E5 v2 Product Family (based on Ivy Bridge-E microarchitecture) + Table 35-27. Additional MSRs Supported by Processors based on the Haswell or Haswell-E microarchitectures + Table 35-40. Selected MSRs Supported by Next Generation Intel® Xeon Phiâ„¢ Processors with DisplayFamily_DisplayModel Signature 06_57H + MSR_PLATFORM_INFO[15:8] is Maximum Non-Turbo Ratio */ + err = cpu_rdmsr_range(info->handle, MSR_PLATFORM_INFO, 15, 8, ®); + if (!err) return (double) info->cpu_clock / reg; + } + else if(info->id->vendor == VENDOR_AMD) { + /* Refer links above + MSRC001_0061[6:4] is PstateMaxVal + PstateMaxVal is the the lowest-performance non-boosted P-state */ + addr = get_amd_last_pstate_addr(info); + err = cpu_rdmsr_range(info->handle, MSR_PSTATE_L, 6, 4, ®); + err += get_amd_multipliers(info, addr - reg, &mult); + if (!err) return (double) info->cpu_clock / mult; + } + + return (double) CPU_INVALID_VALUE / 100; +} + +int cpu_rdmsr_range(struct msr_driver_t* handle, uint32_t msr_index, uint8_t highbit, + uint8_t lowbit, uint64_t* result) +{ + int err; + const uint8_t bits = highbit - lowbit + 1; + + if(highbit > 63 || lowbit > highbit) + return set_error(ERR_INVRANGE); + + err = cpu_rdmsr(handle, msr_index, result); + + if(!err && bits < 64) { + /* Show only part of register */ + *result >>= lowbit; + *result &= (1ULL << bits) - 1; + } + + return err; +} + +int cpu_msrinfo(struct msr_driver_t* handle, cpu_msrinfo_request_t which) +{ + static int err = 0, init = 0; + struct cpu_raw_data_t raw; + static struct cpu_id_t id; + static struct internal_id_info_t internal; + static struct msr_info_t info; + + if (handle == NULL) { + set_error(ERR_HANDLE); + return CPU_INVALID_VALUE; + } + + info.handle = handle; + if (!init) { + err = cpuid_get_raw_data(&raw); + err += cpu_ident_internal(&raw, &id, &internal); + info.cpu_clock = cpu_clock_measure(250, 1); + info.id = &id; + info.internal = &internal; + init = 1; + } + + if (err) + return CPU_INVALID_VALUE; + + switch (which) { + case INFO_MPERF: + return perfmsr_measure(handle, IA32_MPERF); + case INFO_APERF: + return perfmsr_measure(handle, IA32_APERF); + case INFO_MIN_MULTIPLIER: + return (int) (get_info_min_multiplier(&info) * 100); + case INFO_CUR_MULTIPLIER: + return (int) (get_info_cur_multiplier(&info) * 100); + case INFO_MAX_MULTIPLIER: + return (int) (get_info_max_multiplier(&info) * 100); + case INFO_TEMPERATURE: + return get_info_temperature(&info); + case INFO_THROTTLING: + return CPU_INVALID_VALUE; + case INFO_VOLTAGE: + return (int) (get_info_voltage(&info) * 100); + case INFO_BCLK: + case INFO_BUS_CLOCK: + return (int) (get_info_bus_clock(&info) * 100); + default: + return CPU_INVALID_VALUE; + } +} + +int msr_serialize_raw_data(struct msr_driver_t* handle, const char* filename) +{ + int i, j; + FILE *f; + uint64_t reg; + const uint32_t *msr; + struct cpu_raw_data_t raw; + struct cpu_id_t id; + struct internal_id_info_t internal; + + if (handle == NULL) + return set_error(ERR_HANDLE); + + if (!strcmp(filename, "")) + f = stdout; + else + f = fopen(filename, "wt"); + if (!f) return set_error(ERR_OPEN); + + if (cpuid_get_raw_data(&raw) || cpu_ident_internal(&raw, &id, &internal)) + return -1; + + fprintf(f, "CPU is %s %s, stock clock is %dMHz.\n", id.vendor_str, id.brand_str, cpu_clock_measure(250, 1)); + if (id.vendor == VENDOR_INTEL) + msr = intel_msr; + else if (id.vendor == VENDOR_AMD) + msr = amd_msr; + else + return set_error(ERR_CPU_UNKN); + + for (i = 0; msr[i] != CPU_INVALID_VALUE; i++) { + cpu_rdmsr(handle, msr[i], ®); + fprintf(f, "msr[%#08x]=", msr[i]); + for (j = 56; j >= 0; j -= 8) + fprintf(f, "%02x ", (int) (reg >> j) & 0xff); + printf("\n"); + } + + if (strcmp(filename, "")) + fclose(f); + return set_error(ERR_OK); +} + +#endif // RDMSR_UNSUPPORTED_OS diff --git a/src/3rdparty/libcpuid/rdtsc.c b/src/3rdparty/libcpuid/rdtsc.c new file mode 100644 index 00000000..df454394 --- /dev/null +++ b/src/3rdparty/libcpuid/rdtsc.c @@ -0,0 +1,320 @@ +/* + * 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. + */ +#include +#include +#include "libcpuid.h" +#include "libcpuid_util.h" +#include "asm-bits.h" +#include "rdtsc.h" + +#ifdef _WIN32 +#include +void sys_precise_clock(uint64_t *result) +{ + double c, f; + LARGE_INTEGER freq, counter; + QueryPerformanceCounter(&counter); + QueryPerformanceFrequency(&freq); + c = (double) counter.QuadPart; + f = (double) freq.QuadPart; + *result = (uint64_t) ( c * 1000000.0 / f ); +} +#else +/* assuming Linux, Mac OS or other POSIX */ +#include +void sys_precise_clock(uint64_t *result) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + *result = (uint64_t) tv.tv_sec * (uint64_t) 1000000 + + (uint64_t) tv.tv_usec; +} +#endif /* _WIN32 */ + +/* out = a - b */ +static void mark_t_subtract(struct cpu_mark_t* a, struct cpu_mark_t* b, struct cpu_mark_t *out) +{ + out->tsc = a->tsc - b->tsc; + out->sys_clock = a->sys_clock - b->sys_clock; +} + +void cpu_tsc_mark(struct cpu_mark_t* mark) +{ + cpu_rdtsc(&mark->tsc); + sys_precise_clock(&mark->sys_clock); +} + +void cpu_tsc_unmark(struct cpu_mark_t* mark) +{ + struct cpu_mark_t temp; + cpu_tsc_mark(&temp); + mark_t_subtract(&temp, mark, mark); +} + + +int cpu_clock_by_mark(struct cpu_mark_t* mark) +{ + uint64_t result; + + /* Check if some subtraction resulted in a negative number: */ + if ((mark->tsc >> 63) != 0 || (mark->sys_clock >> 63) != 0) return -1; + + /* Divide-by-zero check: */ + if (mark->sys_clock == 0) return -1; + + /* Check if the result fits in 32bits */ + result = mark->tsc / mark->sys_clock; + if (result > (uint64_t) 0x7fffffff) return -1; + return (int) result; +} + +#ifdef _WIN32 +int cpu_clock_by_os(void) +{ + HKEY key; + DWORD result; + DWORD size = 4; + + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), 0, KEY_READ, &key) != ERROR_SUCCESS) + return -1; + + if (RegQueryValueEx(key, TEXT("~MHz"), NULL, NULL, (LPBYTE) &result, (LPDWORD) &size) != ERROR_SUCCESS) { + RegCloseKey(key); + return -1; + } + RegCloseKey(key); + + return (int)result; +} +#else +#ifdef __APPLE__ +#include +#include +/* Assuming Mac OS X with hw.cpufrequency sysctl */ +int cpu_clock_by_os(void) +{ + long long result = -1; + size_t size = sizeof(result); + if (sysctlbyname("hw.cpufrequency", &result, &size, NULL, 0)) + return -1; + return (int) (result / (long long) 1000000); +} +#else +/* Assuming Linux with /proc/cpuinfo */ +int cpu_clock_by_os(void) +{ + FILE *f; + char line[1024], *s; + int result; + + f = fopen("/proc/cpuinfo", "rt"); + if (!f) return -1; + + while (fgets(line, sizeof(line), f)) { + if (!strncmp(line, "cpu MHz", 7)) { + s = strchr(line, ':'); + if (s && 1 == sscanf(s, ":%d.", &result)) { + fclose(f); + return result; + } + } + } + fclose(f); + return -1; +} +#endif /* __APPLE__ */ +#endif /* _WIN32 */ + +/* Emulate doing useful CPU intensive work */ +static int busy_loop(int amount) +{ + int i, j, k, s = 0; + static volatile int data[42] = {32, 12, -1, 5, 23, 0 }; + for (i = 0; i < amount; i++) + for (j = 0; j < 65536; j++) + for (k = 0; k < 42; k++) + s += data[k]; + return s; +} + +int busy_loop_delay(int milliseconds) +{ + int cycles = 0, r = 0, first = 1; + uint64_t a, b, c; + sys_precise_clock(&a); + while (1) { + sys_precise_clock(&c); + if ((c - a) / 1000 > milliseconds) return r; + r += busy_loop(cycles); + if (first) { + first = 0; + } else { + if (c - b < 1000) cycles *= 2; + if (c - b > 10000) cycles /= 2; + } + b = c; + } +} + +int cpu_clock_measure(int millis, int quad_check) +{ + struct cpu_mark_t begin[4], end[4], temp, temp2; + int results[4], cycles, n, k, i, j, bi, bj, mdiff, diff, _zero = 0; + uint64_t tl; + + if (millis < 1) return -1; + tl = millis * (uint64_t) 1000; + if (quad_check) + tl /= 4; + n = quad_check ? 4 : 1; + cycles = 1; + for (k = 0; k < n; k++) { + cpu_tsc_mark(&begin[k]); + end[k] = begin[k]; + do { + /* Run busy loop, and fool the compiler that we USE the garbishy + value it calculates */ + _zero |= (1 & busy_loop(cycles)); + cpu_tsc_mark(&temp); + mark_t_subtract(&temp, &end[k], &temp2); + /* If busy loop is too short, increase it */ + if (temp2.sys_clock < tl / 8) + cycles *= 2; + end[k] = temp; + } while (end[k].sys_clock - begin[k].sys_clock < tl); + mark_t_subtract(&end[k], &begin[k], &temp); + results[k] = cpu_clock_by_mark(&temp); + } + if (n == 1) return results[0]; + mdiff = 0x7fffffff; + bi = bj = -1; + for (i = 0; i < 4; i++) { + for (j = i + 1; j < 4; j++) { + diff = results[i] - results[j]; + if (diff < 0) diff = -diff; + if (diff < mdiff) { + mdiff = diff; + bi = i; + bj = j; + } + } + } + if (results[bi] == -1) return -1; + return (results[bi] + results[bj] + _zero) / 2; +} + + +static void adjust_march_ic_multiplier(const struct cpu_id_t* id, int* numerator, int* denom) +{ + /* + * for cpu_clock_by_ic: we need to know how many clocks does a typical ADDPS instruction + * take, when issued in rapid succesion without dependencies. The whole idea of + * cpu_clock_by_ic was that this is easy to determine, at least it was back in 2010. Now + * it's getting progressively more hairy, but here are the current measurements: + * + * 1. For CPUs with 64-bit SSE units, ADDPS issue rate is 0.5 IPC (one insn in 2 clocks) + * 2. For CPUs with 128-bit SSE units, issue rate is exactly 1.0 IPC + * 3. For Bulldozer and later, it is 1.4 IPC (we multiply by 5/7) + * 4. For Skylake and later, it is 1.6 IPC (we multiply by 5/8) + */ + // + if (id->sse_size < 128) { + debugf(1, "SSE execution path is 64-bit\n"); + // on a CPU with half SSE unit length, SSE instructions execute at 0.5 IPC; + // the resulting value must be multiplied by 2: + *numerator = 2; + } else { + debugf(1, "SSE execution path is 128-bit\n"); + } + // + // Bulldozer or later: assume 1.4 IPC + if (id->vendor == VENDOR_AMD && id->ext_family >= 21) { + debugf(1, "cpu_clock_by_ic: Bulldozer (or later) detected, dividing result by 1.4\n"); + *numerator = 5; + *denom = 7; // multiply by 5/7, to divide by 1.4 + } + // + // Skylake or later: assume 1.6 IPC + if (id->vendor == VENDOR_INTEL && id->ext_model >= 94) { + debugf(1, "cpu_clock_by_ic: Skylake (or later) detected, dividing result by 1.6\n"); + *numerator = 5; + *denom = 8; // to divide by 1.6, multiply by 5/8 + } +} + +int cpu_clock_by_ic(int millis, int runs) +{ + int max_value = 0, cur_value, i, ri, cycles_inner, cycles_outer, c; + struct cpu_id_t* id; + uint64_t t0, t1, tl, hz; + int multiplier_numerator = 1, multiplier_denom = 1; + if (millis <= 0 || runs <= 0) return -2; + id = get_cached_cpuid(); + // if there aren't SSE instructions - we can't run the test at all + if (!id || !id->flags[CPU_FEATURE_SSE]) return -1; + // + adjust_march_ic_multiplier(id, &multiplier_numerator, &multiplier_denom); + // + tl = millis * 125; // (*1000 / 8) + cycles_inner = 128; + cycles_outer = 1; + do { + if (cycles_inner < 1000000000) cycles_inner *= 2; + else cycles_outer *= 2; + sys_precise_clock(&t0); + for (i = 0; i < cycles_outer; i++) + busy_sse_loop(cycles_inner); + sys_precise_clock(&t1); + } while (t1 - t0 < tl); + debugf(2, "inner: %d, outer: %d\n", cycles_inner, cycles_outer); + for (ri = 0; ri < runs; ri++) { + sys_precise_clock(&t0); + c = 0; + do { + c++; + for (i = 0; i < cycles_outer; i++) + busy_sse_loop(cycles_inner); + sys_precise_clock(&t1); + } while (t1 - t0 < tl * (uint64_t) 8); + // cpu_Hz = cycles_inner * cycles_outer * 256 / (t1 - t0) * 1000000 + debugf(2, "c = %d, td = %d\n", c, (int) (t1 - t0)); + hz = ((uint64_t) cycles_inner * (uint64_t) 256 + 12) * + (uint64_t) cycles_outer * (uint64_t) multiplier_numerator * (uint64_t) c * (uint64_t) 1000000 + / ((t1 - t0) * (uint64_t) multiplier_denom); + cur_value = (int) (hz / 1000000); + if (cur_value > max_value) max_value = cur_value; + } + return max_value; +} + +int cpu_clock(void) +{ + int result; + result = cpu_clock_by_os(); + if (result <= 0) + result = cpu_clock_measure(200, 1); + return result; +} diff --git a/src/3rdparty/libcpuid/rdtsc.h b/src/3rdparty/libcpuid/rdtsc.h new file mode 100644 index 00000000..b4aaf99a --- /dev/null +++ b/src/3rdparty/libcpuid/rdtsc.h @@ -0,0 +1,33 @@ +/* + * Copyright 2010 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 __RDTSC_H__ +#define __RDTSC_H__ + +void sys_precise_clock(uint64_t *result); +int busy_loop_delay(int milliseconds); + + +#endif /* __RDTSC_H__ */ diff --git a/src/3rdparty/libcpuid/recog_amd.c b/src/3rdparty/libcpuid/recog_amd.c index 352d733b..3867aa8c 100644 --- a/src/3rdparty/libcpuid/recog_amd.c +++ b/src/3rdparty/libcpuid/recog_amd.c @@ -51,6 +51,237 @@ enum _amd_model_codes_t { _1600, }; + +const struct match_entry_t cpudb_amd[] = { + { -1, -1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown AMD CPU" }, + + /* 486 and the likes */ + { 4, -1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown AMD 486" }, + { 4, 3, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "AMD 486DX2" }, + { 4, 7, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "AMD 486DX2WB" }, + { 4, 8, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "AMD 486DX4" }, + { 4, 9, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "AMD 486DX4WB" }, + + /* Pentia clones */ + { 5, -1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown AMD 586" }, + { 5, 0, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K5" }, + { 5, 1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K5" }, + { 5, 2, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K5" }, + { 5, 3, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K5" }, + + /* The K6 */ + { 5, 6, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K6" }, + { 5, 7, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K6" }, + + { 5, 8, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K6-2" }, + { 5, 9, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K6-III" }, + { 5, 10, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown K6" }, + { 5, 11, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown K6" }, + { 5, 12, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown K6" }, + { 5, 13, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "K6-2+" }, + + /* Athlon et al. */ + { 6, 1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Athlon (Slot-A)" }, + { 6, 2, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Athlon (Slot-A)" }, + { 6, 3, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Duron (Spitfire)" }, + { 6, 4, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Athlon (ThunderBird)" }, + + { 6, 6, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown Athlon" }, + { 6, 6, -1, -1, -1, 1, -1, -1, NC, ATHLON_ , 0, "Athlon (Palomino)" }, + { 6, 6, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_MP_ , 0, "Athlon MP (Palomino)" }, + { 6, 6, -1, -1, -1, 1, -1, -1, NC, DURON_ , 0, "Duron (Palomino)" }, + { 6, 6, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_XP_ , 0, "Athlon XP" }, + + { 6, 7, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown Athlon XP" }, + { 6, 7, -1, -1, -1, 1, -1, -1, NC, DURON_ , 0, "Duron (Morgan)" }, + + { 6, 8, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Athlon XP" }, + { 6, 8, -1, -1, -1, 1, -1, -1, NC, ATHLON_ , 0, "Athlon XP (Thoroughbred)" }, + { 6, 8, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_XP_ , 0, "Athlon XP (Thoroughbred)" }, + { 6, 8, -1, -1, -1, 1, -1, -1, NC, DURON_ , 0, "Duron (Applebred)" }, + { 6, 8, -1, -1, -1, 1, -1, -1, NC, SEMPRON_ , 0, "Sempron (Thoroughbred)" }, + { 6, 8, -1, -1, -1, 1, 128, -1, NC, SEMPRON_ , 0, "Sempron (Thoroughbred)" }, + { 6, 8, -1, -1, -1, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron (Thoroughbred)" }, + { 6, 8, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_MP_ , 0, "Athlon MP (Thoroughbred)" }, + { 6, 8, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_XP_|_M_ , 0, "Mobile Athlon (T-Bred)" }, + { 6, 8, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_XP_|_M_|_LV_, 0, "Mobile Athlon (T-Bred)" }, + + { 6, 10, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Athlon XP (Barton)" }, + { 6, 10, -1, -1, -1, 1, 512, -1, NC, ATHLON_|_XP_ , 0, "Athlon XP (Barton)" }, + { 6, 10, -1, -1, -1, 1, 512, -1, NC, SEMPRON_ , 0, "Sempron (Barton)" }, + { 6, 10, -1, -1, -1, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron (Thorton)" }, + { 6, 10, -1, -1, -1, 1, 256, -1, NC, ATHLON_|_XP_ , 0, "Athlon XP (Thorton)" }, + { 6, 10, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_MP_ , 0, "Athlon MP (Barton)" }, + { 6, 10, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_XP_|_M_ , 0, "Mobile Athlon (Barton)" }, + { 6, 10, -1, -1, -1, 1, -1, -1, NC, ATHLON_|_XP_|_M_|_LV_, 0, "Mobile Athlon (Barton)" }, + + /* K8 Architecture */ + { 15, -1, -1, 15, -1, 1, -1, -1, NC, 0 , 0, "Unknown K8" }, + { 15, -1, -1, 16, -1, 1, -1, -1, NC, 0 , 0, "Unknown K9" }, + + { 15, -1, -1, 15, -1, 1, -1, -1, NC, 0 , 0, "Unknown A64" }, + { 15, -1, -1, 15, -1, 1, -1, -1, NC, OPTERON_ , 0, "Opteron" }, + { 15, -1, -1, 15, -1, 2, -1, -1, NC, OPTERON_|_X2 , 0, "Opteron (Dual Core)" }, + { 15, 3, -1, 15, -1, 1, -1, -1, NC, OPTERON_ , 0, "Opteron" }, + { 15, 3, -1, 15, -1, 2, -1, -1, NC, OPTERON_|_X2 , 0, "Opteron (Dual Core)" }, + { 15, -1, -1, 15, -1, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (512K)" }, + { 15, -1, -1, 15, -1, 1, 1024, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (1024K)" }, + { 15, -1, -1, 15, -1, 1, -1, -1, NC, ATHLON_|_FX , 0, "Athlon FX" }, + { 15, -1, -1, 15, -1, 1, -1, -1, NC, ATHLON_|_64_|_FX , 0, "Athlon 64 FX" }, + { 15, 3, -1, 15, 35, 2, -1, -1, NC, ATHLON_|_64_|_FX , 0, "Athlon 64 FX X2 (Toledo)" }, + { 15, -1, -1, 15, -1, 2, 512, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (512K)" }, + { 15, -1, -1, 15, -1, 2, 1024, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (1024K)" }, + { 15, -1, -1, 15, -1, 1, 512, -1, NC, TURION_|_64_ , 0, "Turion 64 (512K)" }, + { 15, -1, -1, 15, -1, 1, 1024, -1, NC, TURION_|_64_ , 0, "Turion 64 (1024K)" }, + { 15, -1, -1, 15, -1, 2, 512, -1, NC, TURION_|_X2 , 0, "Turion 64 X2 (512K)" }, + { 15, -1, -1, 15, -1, 2, 1024, -1, NC, TURION_|_X2 , 0, "Turion 64 X2 (1024K)" }, + { 15, -1, -1, 15, -1, 1, 128, -1, NC, SEMPRON_ , 0, "A64 Sempron (128K)" }, + { 15, -1, -1, 15, -1, 1, 256, -1, NC, SEMPRON_ , 0, "A64 Sempron (256K)" }, + { 15, -1, -1, 15, -1, 1, 512, -1, NC, SEMPRON_ , 0, "A64 Sempron (512K)" }, + { 15, -1, -1, 15, 0x4f, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (Orleans/512K)" }, + { 15, -1, -1, 15, 0x5f, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (Orleans/512K)" }, + { 15, -1, -1, 15, 0x2f, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (Venice/512K)" }, + { 15, -1, -1, 15, 0x2c, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (Venice/512K)" }, + { 15, -1, -1, 15, 0x1f, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (Winchester/512K)" }, + { 15, -1, -1, 15, 0x0c, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (Newcastle/512K)" }, + { 15, -1, -1, 15, 0x27, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (San Diego/512K)" }, + { 15, -1, -1, 15, 0x37, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (San Diego/512K)" }, + { 15, -1, -1, 15, 0x04, 1, 512, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (ClawHammer/512K)" }, + + { 15, -1, -1, 15, 0x5f, 1, 1024, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (Orleans/1024K)" }, + { 15, -1, -1, 15, 0x27, 1, 1024, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (San Diego/1024K)" }, + { 15, -1, -1, 15, 0x04, 1, 1024, -1, NC, ATHLON_|_64_ , 0, "Athlon 64 (ClawHammer/1024K)" }, + + { 15, -1, -1, 15, 0x4b, 2, 256, -1, NC, SEMPRON_ , 0, "Athlon 64 X2 (Windsor/256K)" }, + + { 15, -1, -1, 15, 0x23, 2, 512, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (Toledo/512K)" }, + { 15, -1, -1, 15, 0x4b, 2, 512, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (Windsor/512K)" }, + { 15, -1, -1, 15, 0x43, 2, 512, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (Windsor/512K)" }, + { 15, -1, -1, 15, 0x6b, 2, 512, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (Brisbane/512K)" }, + { 15, -1, -1, 15, 0x2b, 2, 512, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (Manchester/512K)"}, + + { 15, -1, -1, 15, 0x23, 2, 1024, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (Toledo/1024K)" }, + { 15, -1, -1, 15, 0x43, 2, 1024, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon 64 X2 (Windsor/1024K)" }, + + { 15, -1, -1, 15, 0x08, 1, 128, -1, NC, MOBILE_|SEMPRON_ , 0, "Mobile Sempron 64 (Dublin/128K)"}, + { 15, -1, -1, 15, 0x08, 1, 256, -1, NC, MOBILE_|SEMPRON_ , 0, "Mobile Sempron 64 (Dublin/256K)"}, + { 15, -1, -1, 15, 0x0c, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron 64 (Paris)" }, + { 15, -1, -1, 15, 0x1c, 1, 128, -1, NC, SEMPRON_ , 0, "Sempron 64 (Palermo/128K)" }, + { 15, -1, -1, 15, 0x1c, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron 64 (Palermo/256K)" }, + { 15, -1, -1, 15, 0x1c, 1, 128, -1, NC, MOBILE_| SEMPRON_ , 0, "Mobile Sempron 64 (Sonora/128K)"}, + { 15, -1, -1, 15, 0x1c, 1, 256, -1, NC, MOBILE_| SEMPRON_ , 0, "Mobile Sempron 64 (Sonora/256K)"}, + { 15, -1, -1, 15, 0x2c, 1, 128, -1, NC, SEMPRON_ , 0, "Sempron 64 (Palermo/128K)" }, + { 15, -1, -1, 15, 0x2c, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron 64 (Palermo/256K)" }, + { 15, -1, -1, 15, 0x2c, 1, 128, -1, NC, MOBILE_| SEMPRON_ , 0, "Mobile Sempron 64 (Albany/128K)"}, + { 15, -1, -1, 15, 0x2c, 1, 256, -1, NC, MOBILE_| SEMPRON_ , 0, "Mobile Sempron 64 (Albany/256K)"}, + { 15, -1, -1, 15, 0x2f, 1, 128, -1, NC, SEMPRON_ , 0, "Sempron 64 (Palermo/128K)" }, + { 15, -1, -1, 15, 0x2f, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron 64 (Palermo/256K)" }, + { 15, -1, -1, 15, 0x4f, 1, 128, -1, NC, SEMPRON_ , 0, "Sempron 64 (Manila/128K)" }, + { 15, -1, -1, 15, 0x4f, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron 64 (Manila/256K)" }, + { 15, -1, -1, 15, 0x5f, 1, 128, -1, NC, SEMPRON_ , 0, "Sempron 64 (Manila/128K)" }, + { 15, -1, -1, 15, 0x5f, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron 64 (Manila/256K)" }, + { 15, -1, -1, 15, 0x6b, 2, 256, -1, NC, SEMPRON_ , 0, "Sempron 64 Dual (Sherman/256K)"}, + { 15, -1, -1, 15, 0x6b, 2, 512, -1, NC, SEMPRON_ , 0, "Sempron 64 Dual (Sherman/512K)"}, + { 15, -1, -1, 15, 0x7f, 1, 256, -1, NC, SEMPRON_ , 0, "Sempron 64 (Sparta/256K)" }, + { 15, -1, -1, 15, 0x7f, 1, 512, -1, NC, SEMPRON_ , 0, "Sempron 64 (Sparta/512K)" }, + { 15, -1, -1, 15, 0x4c, 1, 256, -1, NC, MOBILE_| SEMPRON_ , 0, "Mobile Sempron 64 (Keene/256K)"}, + { 15, -1, -1, 15, 0x4c, 1, 512, -1, NC, MOBILE_| SEMPRON_ , 0, "Mobile Sempron 64 (Keene/512K)"}, + { 15, -1, -1, 15, -1, 2, -1, -1, NC, SEMPRON_ , 0, "Sempron Dual Core" }, + + { 15, -1, -1, 15, 0x24, 1, 512, -1, NC, TURION_|_64_ , 0, "Turion 64 (Lancaster/512K)" }, + { 15, -1, -1, 15, 0x24, 1, 1024, -1, NC, TURION_|_64_ , 0, "Turion 64 (Lancaster/1024K)" }, + { 15, -1, -1, 15, 0x48, 2, 256, -1, NC, TURION_|_X2 , 0, "Turion X2 (Taylor)" }, + { 15, -1, -1, 15, 0x48, 2, 512, -1, NC, TURION_|_X2 , 0, "Turion X2 (Trinidad)" }, + { 15, -1, -1, 15, 0x4c, 1, 512, -1, NC, TURION_|_64_ , 0, "Turion 64 (Richmond)" }, + { 15, -1, -1, 15, 0x68, 2, 256, -1, NC, TURION_|_X2 , 0, "Turion X2 (Tyler/256K)" }, + { 15, -1, -1, 15, 0x68, 2, 512, -1, NC, TURION_|_X2 , 0, "Turion X2 (Tyler/512K)" }, + { 15, -1, -1, 17, 3, 2, 512, -1, NC, TURION_|_X2 , 0, "Turion X2 (Griffin/512K)" }, + { 15, -1, -1, 17, 3, 2, 1024, -1, NC, TURION_|_X2 , 0, "Turion X2 (Griffin/1024K)" }, + + /* K10 Architecture (2007) */ + { 15, -1, -1, 16, -1, 1, -1, -1, PHENOM, 0 , 0, "Unknown AMD Phenom" }, + { 15, 2, -1, 16, -1, 1, -1, -1, PHENOM, 0 , 0, "Phenom" }, + { 15, 2, -1, 16, -1, 3, -1, -1, PHENOM, 0 , 0, "Phenom X3 (Toliman)" }, + { 15, 2, -1, 16, -1, 4, -1, -1, PHENOM, 0 , 0, "Phenom X4 (Agena)" }, + { 15, 2, -1, 16, -1, 3, 512, -1, PHENOM, 0 , 0, "Phenom X3 (Toliman/256K)" }, + { 15, 2, -1, 16, -1, 3, 512, -1, PHENOM, 0 , 0, "Phenom X3 (Toliman/512K)" }, + { 15, 2, -1, 16, -1, 4, 128, -1, PHENOM, 0 , 0, "Phenom X4 (Agena/128K)" }, + { 15, 2, -1, 16, -1, 4, 256, -1, PHENOM, 0 , 0, "Phenom X4 (Agena/256K)" }, + { 15, 2, -1, 16, -1, 4, 512, -1, PHENOM, 0 , 0, "Phenom X4 (Agena/512K)" }, + { 15, 2, -1, 16, -1, 2, 512, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon X2 (Kuma)" }, + /* Phenom II derivates: */ + { 15, 4, -1, 16, -1, 4, -1, -1, NC, 0 , 0, "Phenom (Deneb-based)" }, + { 15, 4, -1, 16, -1, 1, 1024, -1, NC, SEMPRON_ , 0, "Sempron (Sargas)" }, + { 15, 4, -1, 16, -1, 2, 512, -1, PHENOM2, 0 , 0, "Phenom II X2 (Callisto)" }, + { 15, 4, -1, 16, -1, 3, 512, -1, PHENOM2, 0 , 0, "Phenom II X3 (Heka)" }, + { 15, 4, -1, 16, -1, 4, 512, -1, PHENOM2, 0 , 0, "Phenom II X4" }, + { 15, 4, -1, 16, 4, 4, 512, -1, PHENOM2, 0 , 0, "Phenom II X4 (Deneb)" }, + { 15, 5, -1, 16, 5, 4, 512, -1, PHENOM2, 0 , 0, "Phenom II X4 (Deneb)" }, + { 15, 4, -1, 16, 10, 4, 512, -1, PHENOM2, 0 , 0, "Phenom II X4 (Zosma)" }, + { 15, 4, -1, 16, 10, 6, 512, -1, PHENOM2, 0 , 0, "Phenom II X6 (Thuban)" }, + /* Athlon II derivates: */ + { 15, 6, -1, 16, 6, 2, 512, -1, NC, ATHLON_|_X2 , 0, "Athlon II (Champlain)" }, + { 15, 6, -1, 16, 6, 2, 512, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon II X2 (Regor)" }, + { 15, 6, -1, 16, 6, 2, 1024, -1, NC, ATHLON_|_64_|_X2 , 0, "Athlon II X2 (Regor)" }, + { 15, 5, -1, 16, 5, 3, 512, -1, NC, ATHLON_|_64_|_X3 , 0, "Athlon II X3 (Rana)" }, + { 15, 5, -1, 16, 5, 4, 512, -1, NC, ATHLON_|_64_|_X4 , 0, "Athlon II X4 (Propus)" }, + /* Llano APUs (2011): */ + { 15, 1, -1, 18, 1, 2, -1, -1, FUSION_EA, 0 , 0, "Llano X2" }, + { 15, 1, -1, 18, 1, 3, -1, -1, FUSION_EA, 0 , 0, "Llano X3" }, + { 15, 1, -1, 18, 1, 4, -1, -1, FUSION_EA, 0 , 0, "Llano X4" }, + + /* Family 14h: Bobcat Architecture (2011) */ + { 15, 2, -1, 20, -1, 1, -1, -1, FUSION_C, 0 , 0, "Brazos Ontario" }, + { 15, 2, -1, 20, -1, 2, -1, -1, FUSION_C, 0 , 0, "Brazos Ontario (Dual-core)" }, + { 15, 1, -1, 20, -1, 1, -1, -1, FUSION_E, 0 , 0, "Brazos Zacate" }, + { 15, 1, -1, 20, -1, 2, -1, -1, FUSION_E, 0 , 0, "Brazos Zacate (Dual-core)" }, + { 15, 2, -1, 20, -1, 2, -1, -1, FUSION_Z, 0 , 0, "Brazos Desna (Dual-core)" }, + + /* Family 15h: Bulldozer Architecture (2011) */ + { 15, -1, -1, 21, 0, 4, -1, -1, NC, 0 , 0, "Bulldozer X2" }, + { 15, -1, -1, 21, 1, 4, -1, -1, NC, 0 , 0, "Bulldozer X2" }, + { 15, -1, -1, 21, 1, 6, -1, -1, NC, 0 , 0, "Bulldozer X3" }, + { 15, -1, -1, 21, 1, 8, -1, -1, NC, 0 , 0, "Bulldozer X4" }, + /* 2nd-gen, Piledriver core (2012): */ + { 15, -1, -1, 21, 2, 4, -1, -1, NC, 0 , 0, "Vishera X2" }, + { 15, -1, -1, 21, 2, 6, -1, -1, NC, 0 , 0, "Vishera X3" }, + { 15, -1, -1, 21, 2, 8, -1, -1, NC, 0 , 0, "Vishera X4" }, + { 15, 0, -1, 21, 16, 2, -1, -1, FUSION_A, 0 , 0, "Trinity X2" }, + { 15, 0, -1, 21, 16, 4, -1, -1, FUSION_A, 0 , 0, "Trinity X4" }, + { 15, 3, -1, 21, 19, 2, -1, -1, FUSION_A, 0 , 0, "Richland X2" }, + { 15, 3, -1, 21, 19, 4, -1, -1, FUSION_A, 0 , 0, "Richland X4" }, + /* 3rd-gen, Steamroller core (2014): */ + { 15, 0, -1, 21, 48, 2, -1, -1, FUSION_A, 0 , 0, "Kaveri X2" }, + { 15, 0, -1, 21, 48, 4, -1, -1, FUSION_A, 0 , 0, "Kaveri X4" }, + { 15, 8, -1, 21, 56, 4, -1, -1, FUSION_A, 0 , 0, "Godavari X4" }, + /* 4th-gen, Excavator core (2015): */ + { 15, 1, -1, 21, 96, 2, -1, -1, FUSION_A, 0 , 0, "Carrizo X2" }, + { 15, 1, -1, 21, 96, 4, -1, -1, FUSION_A, 0 , 0, "Carrizo X4" }, + { 15, 5, -1, 21, 101, 2, -1, -1, FUSION_A, 0 , 0, "Bristol Ridge X2" }, + { 15, 5, -1, 21, 101, 4, -1, -1, FUSION_A, 0 , 0, "Bristol Ridge X4" }, + { 15, 0, -1, 21, 112, 2, -1, -1, FUSION_A, 0 , 0, "Stoney Ridge X2" }, + { 15, 0, -1, 21, 112, 2, -1, -1, FUSION_E, 0 , 0, "Stoney Ridge X2" }, + + /* Family 16h: Jaguar Architecture (2013) */ + { 15, 0, -1, 22, 0, 2, -1, -1, FUSION_A, 0 , 0, "Kabini X2" }, + { 15, 0, -1, 22, 0, 4, -1, -1, FUSION_A, 0 , 0, "Kabini X4" }, + /* 2nd-gen, Puma core (2013): */ + { 15, 0, -1, 22, 48, 2, -1, -1, FUSION_E, 0 , 0, "Mullins X2" }, + { 15, 0, -1, 22, 48, 4, -1, -1, FUSION_A, 0 , 0, "Mullins X4" }, + + /* Family 17h: Zen Architecture (2017) */ + { 15, -1, -1, 23, 1, 8, -1, -1, NC, 0 , 0, "Ryzen 7" }, + { 15, -1, -1, 23, 1, 6, -1, -1, NC, 0 , _1600, "Ryzen 5" }, + { 15, -1, -1, 23, 1, 4, -1, -1, NC, 0 , _1500, "Ryzen 5" }, + { 15, -1, -1, 23, 1, 4, -1, -1, NC, 0 , _1400, "Ryzen 5" }, + { 15, -1, -1, 23, 1, 4, -1, -1, NC, 0 , 0, "Ryzen 3" }, + //{ 15, -1, -1, 23, 1, 4, -1, -1, NC, 0 , 0, "Raven Ridge" }, //TBA + + /* Newer Opterons: */ + { 15, 9, -1, 22, 9, 8, -1, -1, NC, OPTERON_ , 0, "Magny-Cours Opteron" }, +}; + + static void load_amd_features(struct cpu_raw_data_t* raw, struct cpu_id_t* data) { const struct feature_map_t matchtable_edx81[] = { @@ -160,10 +391,140 @@ static void decode_amd_number_of_cores(struct cpu_raw_data_t* raw, struct cpu_id } } +static int amd_has_turion_modelname(const char *bs) +{ + /* We search for something like TL-60. Ahh, I miss regexes...*/ + int i, l, k; + char code[3] = {0}; + const char* codes[] = { "ML", "MT", "MK", "TK", "TL", "RM", "ZM", "" }; + l = (int) strlen(bs); + for (i = 3; i < l - 2; i++) { + if (bs[i] == '-' && + isupper(bs[i-1]) && isupper(bs[i-2]) && !isupper(bs[i-3]) && + isdigit(bs[i+1]) && isdigit(bs[i+2]) && !isdigit(bs[i+3])) + { + code[0] = bs[i-2]; + code[1] = bs[i-1]; + for (k = 0; codes[k][0]; k++) + if (!strcmp(codes[k], code)) return 1; + } + } + return 0; +} + +static struct amd_code_and_bits_t decode_amd_codename_part1(const char *bs) +{ + amd_code_t code = NC; + uint64_t bits = 0; + struct amd_code_and_bits_t result; + + if (strstr(bs, "Dual Core") || + strstr(bs, "Dual-Core") || + strstr(bs, " X2 ")) + bits |= _X2; + if (strstr(bs, " X4 ")) bits |= _X4; + if (strstr(bs, " X3 ")) bits |= _X3; + if (strstr(bs, "Opteron")) bits |= OPTERON_; + if (strstr(bs, "Phenom")) { + code = (strstr(bs, "II")) ? PHENOM2 : PHENOM; + } + if (amd_has_turion_modelname(bs)) { + bits |= TURION_; + } + if (strstr(bs, "Athlon(tm)")) bits |= ATHLON_; + if (strstr(bs, "Sempron(tm)")) bits |= SEMPRON_; + if (strstr(bs, "Duron")) bits |= DURON_; + if (strstr(bs, " 64 ")) bits |= _64_; + if (strstr(bs, " FX")) bits |= _FX; + if (strstr(bs, " MP")) bits |= _MP_; + if (strstr(bs, "Athlon(tm) 64") || strstr(bs, "Athlon(tm) II X") || match_pattern(bs, "Athlon(tm) X#")) { + bits |= ATHLON_ | _64_; + } + if (strstr(bs, "Turion")) bits |= TURION_; + + if (strstr(bs, "mobile") || strstr(bs, "Mobile")) { + bits |= MOBILE_; + } + + if (strstr(bs, "XP")) bits |= _XP_; + if (strstr(bs, "XP-M")) bits |= _M_; + if (strstr(bs, "(LV)")) bits |= _LV_; + if (strstr(bs, " APU ")) bits |= _APU_; + + if (match_pattern(bs, "C-##")) code = FUSION_C; + if (match_pattern(bs, "E-###")) code = FUSION_E; + if (match_pattern(bs, "Z-##")) code = FUSION_Z; + if (match_pattern(bs, "[EA]#-####")) code = FUSION_EA; + + result.code = code; + result.bits = bits; + return result; +} + +static int decode_amd_ryzen_model_code(const char* bs) +{ + const struct { + int model_code; + const char* match_str; + } patterns[] = { + { _1600, "1600" }, + { _1500, "1500" }, + { _1400, "1400" }, + }; + int i; + + for (i = 0; i < COUNT_OF(patterns); i++) + if (strstr(bs, patterns[i].match_str)) + return patterns[i].model_code; + // + return 0; +} + +static void decode_amd_codename(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal) +{ + struct amd_code_and_bits_t code_and_bits = decode_amd_codename_part1(data->brand_str); + int i = 0; + char* code_str = NULL; + int model_code; + + for (i = 0; i < COUNT_OF(amd_code_str); i++) { + if (code_and_bits.code == amd_code_str[i].code) { + code_str = amd_code_str[i].str; + break; + } + } + if (/*code == ATHLON_64_X2*/ match_all(code_and_bits.bits, ATHLON_|_64_|_X2) && data->l2_cache < 512) { + code_and_bits.bits &= ~(ATHLON_ | _64_); + code_and_bits.bits |= SEMPRON_; + } + if (code_str) + debugf(2, "Detected AMD brand code: %d (%s)\n", code_and_bits.code, code_str); + else + debugf(2, "Detected AMD brand code: %d\n", code_and_bits.code); + + if (code_and_bits.bits) { + debugf(2, "Detected AMD bits: "); + debug_print_lbits(2, code_and_bits.bits); + } + // is it Ryzen? if so, we need to detect discern between the four-core 1400/1500 (Ryzen 5) and the four-core Ryzen 3: + model_code = (data->ext_family == 23) ? decode_amd_ryzen_model_code(data->brand_str) : 0; + + internal->code.amd = code_and_bits.code; + internal->bits = code_and_bits.bits; + internal->score = match_cpu_codename(cpudb_amd, COUNT_OF(cpudb_amd), data, code_and_bits.code, + code_and_bits.bits, model_code); +} + int cpuid_identify_amd(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal) { load_amd_features(raw, data); decode_amd_cache_info(raw, data); decode_amd_number_of_cores(raw, data); + decode_amd_codename(raw, data, internal); return 0; } + +void cpuid_get_list_amd(struct cpu_list_t* list) +{ + generic_get_cpu_list(cpudb_amd, COUNT_OF(cpudb_amd), list); +} diff --git a/src/3rdparty/libcpuid/recog_amd.h b/src/3rdparty/libcpuid/recog_amd.h index 19f839ba..34e89598 100644 --- a/src/3rdparty/libcpuid/recog_amd.h +++ b/src/3rdparty/libcpuid/recog_amd.h @@ -27,5 +27,6 @@ #define __RECOG_AMD_H__ int cpuid_identify_amd(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal); +void cpuid_get_list_amd(struct cpu_list_t* list); #endif /* __RECOG_AMD_H__ */ diff --git a/src/3rdparty/libcpuid/recog_intel.c b/src/3rdparty/libcpuid/recog_intel.c index 5467c19f..5e6c03b0 100644 --- a/src/3rdparty/libcpuid/recog_intel.c +++ b/src/3rdparty/libcpuid/recog_intel.c @@ -59,6 +59,291 @@ enum _intel_model_t { }; typedef enum _intel_model_t intel_model_t; +const struct match_entry_t cpudb_intel[] = { + { -1, -1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown Intel CPU" }, + + /* i486 */ + { 4, -1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown i486" }, + { 4, 0, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "i486 DX-25/33" }, + { 4, 1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "i486 DX-50" }, + { 4, 2, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "i486 SX" }, + { 4, 3, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "i486 DX2" }, + { 4, 4, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "i486 SL" }, + { 4, 5, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "i486 SX2" }, + { 4, 7, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "i486 DX2 WriteBack" }, + { 4, 8, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "i486 DX4" }, + { 4, 9, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "i486 DX4 WriteBack" }, + + /* All Pentia: + Pentium 1 */ + { 5, -1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown Pentium" }, + { 5, 0, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Pentium A-Step" }, + { 5, 1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Pentium 1 (0.8u)" }, + { 5, 2, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Pentium 1 (0.35u)" }, + { 5, 3, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Pentium OverDrive" }, + { 5, 4, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Pentium 1 (0.35u)" }, + { 5, 7, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Pentium 1 (0.35u)" }, + { 5, 8, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Pentium MMX (0.25u)" }, + + /* Pentium 2 / 3 / M / Conroe / whatsnext - all P6 based. */ + { 6, -1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown P6" }, + { 6, 0, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Pentium Pro" }, + { 6, 1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Pentium Pro" }, + { 6, 3, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Pentium II (Klamath)" }, + { 6, 5, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Pentium II (Deschutes)" }, + { 6, 5, -1, -1, -1, 1, -1, -1, NC, MOBILE_|PENTIUM_, 0, "Mobile Pentium II (Tonga)"}, + { 6, 6, -1, -1, -1, 1, -1, -1, NC,0 , 0, "Pentium II (Dixon)" }, + + { 6, 3, -1, -1, -1, 1, -1, -1, NC, XEON_ , 0, "P-II Xeon (Klamath)" }, + { 6, 5, -1, -1, -1, 1, -1, -1, NC, XEON_ , 0, "P-II Xeon (Drake)" }, + { 6, 6, -1, -1, -1, 1, -1, -1, NC, XEON_ , 0, "P-II Xeon (Dixon)" }, + + { 6, 5, -1, -1, -1, 1, -1, -1, NC, CELERON_ , 0, "P-II Celeron (Covington)" }, + { 6, 6, -1, -1, -1, 1, -1, -1, NC, CELERON_ , 0, "P-II Celeron (Mendocino)" }, + + /* -------------------------------------------------- */ + + { 6, 7, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Pentium III (Katmai)" }, + { 6, 8, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Pentium III (Coppermine)"}, + { 6, 10, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Pentium III (Coppermine)"}, + { 6, 11, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Pentium III (Tualatin)" }, + + { 6, 7, -1, -1, -1, 1, -1, -1, NC, XEON_ , 0, "P-III Xeon (Tanner)" }, + { 6, 8, -1, -1, -1, 1, -1, -1, NC, XEON_ , 0, "P-III Xeon (Cascades)" }, + { 6, 10, -1, -1, -1, 1, -1, -1, NC, XEON_ , 0, "P-III Xeon (Cascades)" }, + { 6, 11, -1, -1, -1, 1, -1, -1, NC, XEON_ , 0, "P-III Xeon (Tualatin)" }, + + { 6, 7, -1, -1, -1, 1, -1, -1, NC, CELERON_ , 0, "P-III Celeron (Katmai)" }, + { 6, 8, -1, -1, -1, 1, -1, -1, NC, CELERON_ , 0, "P-III Celeron (Coppermine)" }, + { 6, 10, -1, -1, -1, 1, -1, -1, NC, CELERON_ , 0, "P-III Celeron (Coppermine)" }, + { 6, 11, -1, -1, -1, 1, -1, -1, NC, CELERON_ , 0, "P-III Celeron (Tualatin)" }, + + /* Netburst based (Pentium 4 and later) + classic P4s */ + { 15, -1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown Pentium 4" }, + { 15, -1, -1, 15, -1, 1, -1, -1, NC, CELERON_ , 0, "Unknown P-4 Celeron" }, + { 15, -1, -1, 15, -1, 1, -1, -1, NC, XEON_ , 0, "Unknown Xeon" }, + + { 15, 0, -1, 15, -1, 1, -1, -1, NC, PENTIUM_ , 0, "Pentium 4 (Willamette)" }, + { 15, 1, -1, 15, -1, 1, -1, -1, NC, PENTIUM_ , 0, "Pentium 4 (Willamette)" }, + { 15, 2, -1, 15, -1, 1, -1, -1, NC, PENTIUM_ , 0, "Pentium 4 (Northwood)" }, + { 15, 3, -1, 15, -1, 1, -1, -1, NC, PENTIUM_ , 0, "Pentium 4 (Prescott)" }, + { 15, 4, -1, 15, -1, 1, -1, -1, NC, PENTIUM_ , 0, "Pentium 4 (Prescott)" }, + { 15, 6, -1, 15, -1, 1, -1, -1, NC, PENTIUM_ , 0, "Pentium 4 (Cedar Mill)" }, + { 15, 0, -1, 15, -1, 1, -1, -1, NC, MOBILE_|PENTIUM_, 0, "Mobile P-4 (Willamette)" }, + { 15, 1, -1, 15, -1, 1, -1, -1, NC, MOBILE_|PENTIUM_, 0, "Mobile P-4 (Willamette)" }, + { 15, 2, -1, 15, -1, 1, -1, -1, NC, MOBILE_|PENTIUM_, 0, "Mobile P-4 (Northwood)" }, + { 15, 3, -1, 15, -1, 1, -1, -1, NC, MOBILE_|PENTIUM_, 0, "Mobile P-4 (Prescott)" }, + { 15, 4, -1, 15, -1, 1, -1, -1, NC, MOBILE_|PENTIUM_, 0, "Mobile P-4 (Prescott)" }, + { 15, 6, -1, 15, -1, 1, -1, -1, NC, MOBILE_|PENTIUM_, 0, "Mobile P-4 (Cedar Mill)" }, + + /* server CPUs */ + { 15, 0, -1, 15, -1, 1, -1, -1, NC, XEON_ , 0, "Xeon (Foster)" }, + { 15, 1, -1, 15, -1, 1, -1, -1, NC, XEON_ , 0, "Xeon (Foster)" }, + { 15, 2, -1, 15, -1, 1, -1, -1, NC, XEON_ , 0, "Xeon (Prestonia)" }, + { 15, 2, -1, 15, -1, 1, -1, -1, NC, XEON_|_MP_ , 0, "Xeon (Gallatin)" }, + { 15, 3, -1, 15, -1, 1, -1, -1, NC, XEON_ , 0, "Xeon (Nocona)" }, + { 15, 4, -1, 15, -1, 1, -1, -1, NC, XEON_ , 0, "Xeon (Nocona)" }, + { 15, 4, -1, 15, -1, 1, -1, -1, IRWIN, XEON_ , 0, "Xeon (Irwindale)" }, + { 15, 4, -1, 15, -1, 1, -1, -1, NC, XEON_|_MP_ , 0, "Xeon (Cranford)" }, + { 15, 4, -1, 15, -1, 1, -1, -1, POTOMAC, XEON_ , 0, "Xeon (Potomac)" }, + { 15, 6, -1, 15, -1, 1, -1, -1, NC, XEON_ , 0, "Xeon (Dempsey)" }, + + /* Pentium Ds */ + { 15, 4, 4, 15, -1, 1, -1, -1, NC, 0 , 0, "Pentium D (SmithField)" }, + { 15, 4, -1, 15, -1, 1, -1, -1, PENTIUM_D, 0 , 0, "Pentium D (SmithField)" }, + { 15, 4, 7, 15, -1, 1, -1, -1, NC, 0 , 0, "Pentium D (SmithField)" }, + { 15, 6, -1, 15, -1, 1, -1, -1, PENTIUM_D, 0 , 0, "Pentium D (Presler)" }, + + /* Celeron and Celeron Ds */ + { 15, 1, -1, 15, -1, 1, -1, -1, NC, CELERON_ , 0, "P-4 Celeron (Willamette)" }, + { 15, 2, -1, 15, -1, 1, -1, -1, NC, CELERON_ , 0, "P-4 Celeron (Northwood)" }, + { 15, 3, -1, 15, -1, 1, -1, -1, NC, CELERON_ , 0, "P-4 Celeron D (Prescott)" }, + { 15, 4, -1, 15, -1, 1, -1, -1, NC, CELERON_ , 0, "P-4 Celeron D (Prescott)" }, + { 15, 6, -1, 15, -1, 1, -1, -1, NC, CELERON_ , 0, "P-4 Celeron D (Cedar Mill)" }, + + /* -------------------------------------------------- */ + /* Intel Core microarchitecture - P6-based */ + + { 6, 9, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown Pentium M" }, + { 6, 9, -1, -1, -1, 1, -1, -1, PENTIUM_M, 0 , 0, "Unknown Pentium M" }, + { 6, 9, -1, -1, -1, 1, -1, -1, NC, PENTIUM_ , 0, "Pentium M (Banias)" }, + { 6, 9, -1, -1, -1, 1, -1, -1, PENTIUM_M, 0 , 0, "Pentium M (Banias)" }, + { 6, 9, -1, -1, -1, 1, -1, -1, NC, CELERON_ , 0, "Celeron M" }, + { 6, 13, -1, -1, -1, 1, -1, -1, NC, PENTIUM_ , 0, "Pentium M (Dothan)" }, + { 6, 13, -1, -1, -1, 1, -1, -1, PENTIUM_M, 0 , 0, "Pentium M (Dothan)" }, + { 6, 13, -1, -1, -1, 1, -1, -1, NC, CELERON_ , 0, "Celeron M" }, + + { 6, 12, -1, -1, -1, -1, -1, -1, NC, ATOM_ , 0, "Unknown Atom" }, + { 6, 12, -1, -1, -1, -1, -1, -1, DIAMONDVILLE,ATOM_, 0, "Atom (Diamondville)" }, + { 6, 12, -1, -1, -1, -1, -1, -1, SILVERTHORNE,ATOM_, 0, "Atom (Silverthorne)" }, + { 6, 12, -1, -1, -1, -1, -1, -1, CEDARVIEW, ATOM_ , 0, "Atom (Cedarview)" }, + { 6, 6, -1, -1, -1, -1, -1, -1, CEDARVIEW, ATOM_ , 0, "Atom (Cedarview)" }, + { 6, 12, -1, -1, -1, -1, -1, -1, PINEVIEW, ATOM_ , 0, "Atom (Pineview)" }, + + /* -------------------------------------------------- */ + + { 6, 14, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown Yonah" }, + { 6, 14, -1, -1, -1, 1, -1, -1, CORE_SOLO, 0 , 0, "Yonah (Core Solo)" }, + { 6, 14, -1, -1, -1, 2, -1, -1, CORE_DUO, 0 , 0, "Yonah (Core Duo)" }, + { 6, 14, -1, -1, -1, 1, -1, -1, CORE_SOLO, MOBILE_, 0, "Yonah (Core Solo)" }, + { 6, 14, -1, -1, -1, 2, -1, -1, CORE_DUO , MOBILE_, 0, "Yonah (Core Duo)" }, + { 6, 14, -1, -1, -1, 1, -1, -1, CORE_SOLO, 0 , 0, "Yonah (Core Solo)" }, + + { 6, 15, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Unknown Core 2" }, + { 6, 15, -1, -1, -1, 2, 4096, -1, CORE_DUO, 0 , 0, "Conroe (Core 2 Duo)" }, + { 6, 15, -1, -1, -1, 2, 1024, -1, CORE_DUO, 0 , 0, "Conroe (Core 2 Duo) 1024K" }, + { 6, 15, -1, -1, -1, 2, 512, -1, CORE_DUO, 0 , 0, "Conroe (Core 2 Duo) 512K" }, + { 6, 15, -1, -1, -1, 4, -1, -1, QUAD_CORE, 0 , 0, "Kentsfield (Core 2 Quad)" }, + { 6, 15, -1, -1, -1, 4, 4096, -1, QUAD_CORE, 0 , 0, "Kentsfield (Core 2 Quad)" }, + { 6, 15, -1, -1, -1, 400, -1, -1, MORE_THAN_QUADCORE, 0, 0, "More than quad-core" }, + { 6, 15, -1, -1, -1, 2, 2048, -1, CORE_DUO, 0 , 0, "Allendale (Core 2 Duo)" }, + { 6, 15, -1, -1, -1, 2, -1, -1, MOBILE_CORE_DUO, 0, 0, "Merom (Core 2 Duo)" }, + { 6, 15, -1, -1, -1, 2, 2048, -1, MEROM, 0 , 0, "Merom (Core 2 Duo) 2048K" }, + { 6, 15, -1, -1, -1, 2, 4096, -1, MEROM, 0 , 0, "Merom (Core 2 Duo) 4096K" }, + + { 6, 15, -1, -1, 15, 1, -1, -1, NC, CELERON_ , 0, "Conroe-L (Celeron)" }, + { 6, 6, -1, -1, 22, 1, -1, -1, NC, CELERON_ , 0, "Conroe-L (Celeron)" }, + { 6, 15, -1, -1, 15, 2, -1, -1, NC, CELERON_ , 0, "Conroe-L (Allendale)" }, + { 6, 6, -1, -1, 22, 2, -1, -1, NC, CELERON_ , 0, "Conroe-L (Allendale)" }, + + + { 6, 6, -1, -1, 22, 1, -1, -1, NC, 0 , 0, "Unknown Core ?" }, + { 6, 7, -1, -1, 23, 1, -1, -1, NC, 0 , 0, "Unknown Core ?" }, + { 6, 6, -1, -1, 22, 400, -1, -1, MORE_THAN_QUADCORE, 0, 0, "More than quad-core" }, + { 6, 7, -1, -1, 23, 400, -1, -1, MORE_THAN_QUADCORE, 0, 0, "More than quad-core" }, + + { 6, 7, -1, -1, 23, 1, -1, -1, CORE_SOLO , 0, 0, "Unknown Core 45nm" }, + { 6, 7, -1, -1, 23, 1, -1, -1, CORE_DUO , 0, 0, "Unknown Core 45nm" }, + { 6, 7, -1, -1, 23, 2, 1024, -1, WOLFDALE , 0, 0, "Celeron Wolfdale 1M" }, + { 6, 7, -1, -1, 23, 2, 2048, -1, WOLFDALE , 0, 0, "Wolfdale (Core 2 Duo) 2M" }, + { 6, 7, -1, -1, 23, 2, 3072, -1, WOLFDALE , 0, 0, "Wolfdale (Core 2 Duo) 3M" }, + { 6, 7, -1, -1, 23, 2, 6144, -1, WOLFDALE , 0, 0, "Wolfdale (Core 2 Duo) 6M" }, + { 6, 7, -1, -1, 23, 1, -1, -1, MOBILE_CORE_DUO , 0, 0, "Penryn (Core 2 Duo)" }, + { 6, 7, -1, -1, 23, 2, 1024, -1, PENRYN , 0, 0, "Penryn (Core 2 Duo)" }, + { 6, 7, -1, -1, 23, 2, 3072, -1, PENRYN , 0, 0, "Penryn (Core 2 Duo) 3M" }, + { 6, 7, -1, -1, 23, 2, 6144, -1, PENRYN , 0, 0, "Penryn (Core 2 Duo) 6M" }, + { 6, 7, -1, -1, 23, 4, 2048, -1, NC , 0, 0, "Yorkfield (Core 2 Quad) 2M"}, + { 6, 7, -1, -1, 23, 4, 3072, -1, NC , 0, 0, "Yorkfield (Core 2 Quad) 3M"}, + { 6, 7, -1, -1, 23, 4, 6144, -1, NC , 0, 0, "Yorkfield (Core 2 Quad) 6M"}, + + /* Core microarchitecture-based Xeons: */ + { 6, 14, -1, -1, 14, 1, -1, -1, NC, XEON_ , 0, "Xeon LV" }, + { 6, 15, -1, -1, 15, 2, 4096, -1, NC, XEON_ , _5100, "Xeon (Woodcrest)" }, + { 6, 15, -1, -1, 15, 2, 2048, -1, NC, XEON_ , _3000, "Xeon (Conroe/2M)" }, + { 6, 15, -1, -1, 15, 2, 4096, -1, NC, XEON_ , _3000, "Xeon (Conroe/4M)" }, + { 6, 15, -1, -1, 15, 4, 4096, -1, NC, XEON_ , X3200, "Xeon (Kentsfield)" }, + { 6, 15, -1, -1, 15, 4, 4096, -1, NC, XEON_ , _5300, "Xeon (Clovertown)" }, + { 6, 7, -1, -1, 23, 2, 6144, -1, NC, XEON_ , _3100, "Xeon (Wolfdale)" }, + { 6, 7, -1, -1, 23, 2, 6144, -1, NC, XEON_ , _5200, "Xeon (Wolfdale DP)" }, + { 6, 7, -1, -1, 23, 4, 6144, -1, NC, XEON_ , _5400, "Xeon (Harpertown)" }, + { 6, 7, -1, -1, 23, 4, 3072, -1, NC, XEON_ , X3300, "Xeon (Yorkfield/3M)" }, + { 6, 7, -1, -1, 23, 4, 6144, -1, NC, XEON_ , X3300, "Xeon (Yorkfield/6M)" }, + + /* Nehalem CPUs (45nm): */ + { 6, 10, -1, -1, 26, 4, -1, -1, GAINESTOWN, XEON_ , 0, "Gainestown (Xeon)" }, + { 6, 10, -1, -1, 26, 4, -1, 4096, GAINESTOWN, XEON_ , 0, "Gainestown 4M (Xeon)" }, + { 6, 10, -1, -1, 26, 4, -1, 8192, GAINESTOWN, XEON_ , 0, "Gainestown 8M (Xeon)" }, + { 6, 10, -1, -1, 26, 4, -1, -1, NC, XEON_|_7 , 0, "Bloomfield (Xeon)" }, + { 6, 10, -1, -1, 26, 4, -1, -1, NC, CORE_|_I_|_7 , 0, "Bloomfield (Core i7)" }, + { 6, 10, -1, -1, 30, 4, -1, -1, NC, CORE_|_I_|_7 , 0, "Lynnfield (Core i7)" }, + { 6, 5, -1, -1, 37, 4, -1, 8192, NC, CORE_|_I_|_5 , 0, "Lynnfield (Core i5)" }, + + /* Westmere CPUs (32nm): */ + { 6, 5, -1, -1, 37, 2, -1, -1, NC, 0 , 0, "Unknown Core i3/i5" }, + { 6, 12, -1, -1, 44, -1, -1, -1, WESTMERE, XEON_ , 0, "Westmere (Xeon)" }, + { 6, 12, -1, -1, 44, -1, -1, 12288, WESTMERE, XEON_ , 0, "Gulftown (Xeon)" }, + { 6, 12, -1, -1, 44, 4, -1, 12288, NC, CORE_|_I_|_7 , 0, "Gulftown (Core i7)" }, + { 6, 5, -1, -1, 37, 2, -1, 4096, NC, CORE_|_I_|_5 , 0, "Clarkdale (Core i5)" }, + { 6, 5, -1, -1, 37, 2, -1, 4096, NC, CORE_|_I_|_3 , 0, "Clarkdale (Core i3)" }, + { 6, 5, -1, -1, 37, 2, -1, -1, NC, PENTIUM_ , 0, "Arrandale" }, + { 6, 5, -1, -1, 37, 2, -1, 4096, NC, CORE_|_I_|_7 , 0, "Arrandale (Core i7)" }, + { 6, 5, -1, -1, 37, 2, -1, 3072, NC, CORE_|_I_|_5 , 0, "Arrandale (Core i5)" }, + { 6, 5, -1, -1, 37, 2, -1, 3072, NC, CORE_|_I_|_3 , 0, "Arrandale (Core i3)" }, + + /* Sandy Bridge CPUs (32nm): */ + { 6, 10, -1, -1, 42, -1, -1, -1, NC, 0 , 0, "Unknown Sandy Bridge" }, + { 6, 10, -1, -1, 42, -1, -1, -1, NC, XEON_ , 0, "Sandy Bridge (Xeon)" }, + { 6, 10, -1, -1, 42, -1, -1, -1, NC, CORE_|_I_|_7 , 0, "Sandy Bridge (Core i7)" }, + { 6, 10, -1, -1, 42, 4, -1, -1, NC, CORE_|_I_|_7 , 0, "Sandy Bridge (Core i7)" }, + { 6, 10, -1, -1, 42, 4, -1, -1, NC, CORE_|_I_|_5 , 0, "Sandy Bridge (Core i5)" }, + { 6, 10, -1, -1, 42, 2, -1, -1, NC, CORE_|_I_|_3 , 0, "Sandy Bridge (Core i3)" }, + { 6, 10, -1, -1, 42, 2, -1, -1, NC, PENTIUM_ , 0, "Sandy Bridge (Pentium)" }, + { 6, 10, -1, -1, 42, 1, -1, -1, NC, CELERON_ , 0, "Sandy Bridge (Celeron)" }, + { 6, 10, -1, -1, 42, 2, -1, -1, NC, CELERON_ , 0, "Sandy Bridge (Celeron)" }, + { 6, 13, -1, -1, 45, -1, -1, -1, NC, CORE_|_I_|_3 , 0, "Sandy Bridge-E" }, + { 6, 13, -1, -1, 45, -1, -1, -1, NC, XEON_ , 0, "Sandy Bridge-E (Xeon)" }, + + /* Ivy Bridge CPUs (22nm): */ + { 6, 10, -1, -1, 58, -1, -1, -1, NC, XEON_ , 0, "Ivy Bridge (Xeon)" }, + { 6, 10, -1, -1, 58, 4, -1, -1, NC, CORE_|_I_|_7 , 0, "Ivy Bridge (Core i7)" }, + { 6, 10, -1, -1, 58, 4, -1, -1, NC, CORE_|_I_|_5 , 0, "Ivy Bridge (Core i5)" }, + { 6, 10, -1, -1, 58, 2, -1, -1, NC, CORE_|_I_|_3 , 0, "Ivy Bridge (Core i3)" }, + { 6, 10, -1, -1, 58, 2, -1, -1, NC, PENTIUM_ , 0, "Ivy Bridge (Pentium)" }, + { 6, 10, -1, -1, 58, 1, -1, -1, NC, CELERON_ , 0, "Ivy Bridge (Celeron)" }, + { 6, 10, -1, -1, 58, 2, -1, -1, NC, CELERON_ , 0, "Ivy Bridge (Celeron)" }, + { 6, 14, -1, -1, 62, -1, -1, -1, NC, 0 , 0, "Ivy Bridge-E" }, + + /* Haswell CPUs (22nm): */ + { 6, 12, -1, -1, 60, -1, -1, -1, NC, XEON_ , 0, "Haswell (Xeon)" }, + { 6, 12, -1, -1, 60, 4, -1, -1, NC, CORE_|_I_|_7 , 0, "Haswell (Core i7)" }, + { 6, 5, -1, -1, 69, 4, -1, -1, NC, CORE_|_I_|_7 , 0, "Haswell (Core i7)" }, + { 6, 6, -1, -1, 70, 4, -1, -1, NC, CORE_|_I_|_7 , 0, "Haswell (Core i7)" }, + { 6, 12, -1, -1, 60, 4, -1, -1, NC, CORE_|_I_|_5 , 0, "Haswell (Core i5)" }, + { 6, 5, -1, -1, 69, 4, -1, -1, NC, CORE_|_I_|_5 , 0, "Haswell (Core i5)" }, + { 6, 12, -1, -1, 60, 2, -1, -1, NC, CORE_|_I_|_5 , 0, "Haswell (Core i5)" }, + { 6, 5, -1, -1, 69, 2, -1, -1, NC, CORE_|_I_|_5 , 0, "Haswell (Core i5)" }, + { 6, 12, -1, -1, 60, 2, -1, -1, NC, CORE_|_I_|_3 , 0, "Haswell (Core i3)" }, + { 6, 5, -1, -1, 69, 2, -1, -1, NC, CORE_|_I_|_3 , 0, "Haswell (Core i3)" }, + { 6, 12, -1, -1, 60, 2, -1, -1, NC, PENTIUM_ , 0, "Haswell (Pentium)" }, + { 6, 12, -1, -1, 60, 2, -1, -1, NC, CELERON_ , 0, "Haswell (Celeron)" }, + { 6, 12, -1, -1, 60, 1, -1, -1, NC, CELERON_ , 0, "Haswell (Celeron)" }, + { 6, 15, -1, -1, 63, -1, -1, -1, NC, 0 , 0, "Haswell-E" }, + + /* Broadwell CPUs (14nm): */ + { 6, 7, -1, -1, 71, 4, -1, -1, NC, CORE_|_I_|_7 , 0, "Broadwell (Core i7)" }, + { 6, 7, -1, -1, 71, 4, -1, -1, NC, CORE_|_I_|_5 , 0, "Broadwell (Core i5)" }, + { 6, 13, -1, -1, 61, 4, -1, -1, NC, CORE_|_I_|_7 , 0, "Broadwell-U (Core i7)" }, + { 6, 13, -1, -1, 61, 2, -1, -1, NC, CORE_|_I_|_7 , 0, "Broadwell-U (Core i7)" }, + { 6, 13, -1, -1, 61, 2, -1, -1, NC, CORE_|_I_|_5 , 0, "Broadwell-U (Core i5)" }, + { 6, 13, -1, -1, 61, 2, -1, -1, NC, CORE_|_I_|_3 , 0, "Broadwell-U (Core i3)" }, + { 6, 13, -1, -1, 61, 2, -1, -1, NC, PENTIUM_ , 0, "Broadwell-U (Pentium)" }, + { 6, 13, -1, -1, 61, 2, -1, -1, NC, CELERON_ , 0, "Broadwell-U (Celeron)" }, + { 6, 13, -1, -1, 61, 2, -1, -1, NA, 0 , 0, "Broadwell-U (Core M)" }, + { 6, 15, -1, -1, 79, -1, -1, -1, NC, XEON_ , 0, "Broadwell-E (Xeon)" }, + { 6, 15, -1, -1, 79, 2, -1, -1, NC, CORE_|_I_|_3 , 0, "Broadwell-E (Core i3)" }, + { 6, 15, -1, -1, 79, 2, -1, -1, NC, CORE_|_I_|_5 , 0, "Broadwell-E (Core i5)" }, + { 6, 15, -1, -1, 79, 4, -1, -1, NC, CORE_|_I_|_5 , 0, "Broadwell-E (Core i5)" }, + { 6, 15, -1, -1, 79, 2, -1, -1, NC, CORE_|_I_|_7 , 0, "Broadwell-E (Core i7)" }, + { 6, 15, -1, -1, 79, 4, -1, -1, NC, CORE_|_I_|_7 , 0, "Broadwell-E (Core i7)" }, + + /* Skylake CPUs (14nm): */ + { 6, 14, -1, -1, 94, -1, -1, -1, NC, XEON_ , 0, "Skylake (Xeon)" }, + { 6, 14, -1, -1, 94, 4, -1, -1, NC, CORE_|_I_|_7 , 0, "Skylake (Core i7)" }, + { 6, 14, -1, -1, 94, 4, -1, -1, NC, CORE_|_I_|_5 , 0, "Skylake (Core i5)" }, + { 6, 14, -1, -1, 94, 2, -1, -1, NC, CORE_|_I_|_3 , 0, "Skylake (Core i3)" }, + { 6, 14, -1, -1, 94, 2, -1, -1, NC, PENTIUM_ , 0, "Skylake (Pentium)" }, + { 6, 14, -1, -1, 78, 2, -1, -1, NC, PENTIUM_ , 0, "Skylake (Pentium)" }, + { 6, 14, -1, -1, 94, 2, -1, -1, NC, CELERON_ , 0, "Skylake (Celeron)" }, + { 6, 14, -1, -1, 78, 2, -1, -1, NC, CELERON_ , 0, "Skylake (Celeron)" }, + { 6, 14, -1, -1, 78, 2, -1, -1, NC, CORE_|_M_|_7 , 0, "Skylake (Core m7)" }, + { 6, 14, -1, -1, 78, 2, -1, -1, NC, CORE_|_M_|_5 , 0, "Skylake (Core m5)" }, + { 6, 14, -1, -1, 78, 2, -1, -1, NC, CORE_|_M_|_3 , 0, "Skylake (Core m3)" }, + + /* Kaby Lake CPUs (14nm): */ + { 6, 14, -1, -1, 158, 4, -1, -1, NC, CORE_|_I_|_7 , 0, "Kaby Lake (Core i7)" }, + { 6, 14, -1, -1, 158, 4, -1, -1, NC, CORE_|_I_|_5 , 0, "Kaby Lake (Core i5)" }, + { 6, 14, -1, -1, 158, 2, -1, -1, NC, CORE_|_I_|_3 , 0, "Kaby Lake (Core i3)" }, + { 6, 14, -1, -1, 158, 2, -1, -1, NC, PENTIUM_ , 0, "Kaby Lake (Pentium)" }, + { 6, 14, -1, -1, 158, 2, -1, -1, NC, CELERON_ , 0, "Kaby Lake (Celeron)" }, + { 6, 14, -1, -1, 158, 2, -1, -1, NC, CORE_|_M_|_3 , 0, "Kaby Lake (Core m3)" }, + + /* Itaniums */ + { 7, -1, -1, -1, -1, 1, -1, -1, NC, 0 , 0, "Itanium" }, + { 15, -1, -1, 16, -1, 1, -1, -1, NC, 0 , 0, "Itanium 2" }, +}; + + static void load_intel_features(struct cpu_raw_data_t* raw, struct cpu_id_t* data) { const struct feature_map_t matchtable_edx1[] = { @@ -273,6 +558,8 @@ static void decode_intel_deterministic_cache_info(struct cpu_raw_data_t* raw, else if (level == 4 && typenumber == 3) type = L4; else { + warnf("deterministic_cache: unknown level/typenumber combo (%d/%d), cannot\n", level, typenumber); + warnf("deterministic_cache: recognize cache type\n"); continue; } ways = ((raw->intel_fn4[ecx][1] >> 22) & 0x3ff) + 1; @@ -394,6 +681,7 @@ static intel_code_and_bits_t get_brand_code_and_bits(struct cpu_id_t* data) code = matchtable[i].c; break; } + debugf(2, "intel matchtable result is %d\n", code); if (bits & XEON_) { if (match_pattern(bs, "W35##") || match_pattern(bs, "[ELXW]75##")) bits |= _7; @@ -455,6 +743,65 @@ static intel_code_and_bits_t get_brand_code_and_bits(struct cpu_id_t* data) return result; } +static intel_model_t get_model_code(struct cpu_id_t* data) +{ + int i = 0; + int l = (int) strlen(data->brand_str); + const char *bs = data->brand_str; + int mod_flags = 0, model_no = 0, ndigs = 0; + /* If the CPU is a Core ix, then just return the model number generation: */ + if ((i = match_pattern(bs, "Core(TM) i[357]")) != 0) { + i += 11; + if (i + 4 >= l) return UNKNOWN; + if (bs[i] == '2') return _2xxx; + if (bs[i] == '3') return _3xxx; + return UNKNOWN; + } + + /* For Core2-based Xeons: */ + while (i < l - 3) { + if (bs[i] == 'C' && bs[i+1] == 'P' && bs[i+2] == 'U') + break; + i++; + } + if (i >= l - 3) return UNKNOWN; + i += 3; + while (i < l - 4 && bs[i] == ' ') i++; + if (i >= l - 4) return UNKNOWN; + while (i < l - 4 && !isdigit(bs[i])) { + if (bs[i] >= 'A' && bs[i] <= 'Z') + mod_flags |= (1 << (bs[i] - 'A')); + i++; + } + if (i >= l - 4) return UNKNOWN; + while (isdigit(bs[i])) { + ndigs++; + model_no = model_no * 10 + (int) (bs[i] - '0'); + i++; + } + if (ndigs != 4) return UNKNOWN; +#define HAVE(ch, flags) ((flags & (1 << ((int)(ch-'A')))) != 0) + switch (model_no / 100) { + case 30: return _3000; + case 31: return _3100; + case 32: + { + return (HAVE('X', mod_flags)) ? X3200 : _3200; + } + case 33: + { + return (HAVE('X', mod_flags)) ? X3300 : _3300; + } + case 51: return _5100; + case 52: return _5200; + case 53: return _5300; + case 54: return _5400; + default: + return UNKNOWN; + } +#undef HAVE +} + static void decode_intel_sgx_features(const struct cpu_raw_data_t* raw, struct cpu_id_t* data) { struct cpu_epc_t epc; @@ -481,11 +828,13 @@ static void decode_intel_sgx_features(const struct cpu_raw_data_t* raw, struct c for (i = 0; i < 1000000; i++) { epc = cpuid_get_epc(i, raw); if (epc.length == 0) { + debugf(2, "SGX: epc section request for %d returned null, no more EPC sections.\n", i); data->sgx.num_epc_sections = i; break; } } if (data->sgx.num_epc_sections == -1) { + debugf(1, "SGX: warning: seems to be infinitude of EPC sections.\n"); data->sgx.num_epc_sections = 1000000; } } @@ -518,6 +867,9 @@ struct cpu_epc_t cpuid_get_epc(int index, const struct cpu_raw_data_t* raw) int cpuid_identify_intel(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal) { intel_code_and_bits_t brand; + intel_model_t model_code; + int i; + char* brand_code_str = NULL; load_intel_features(raw, data); if (raw->basic_cpuid[0][0] >= 4) { @@ -529,14 +881,38 @@ int cpuid_identify_intel(struct cpu_raw_data_t* raw, struct cpu_id_t* data, stru decode_intel_number_of_cores(raw, data); brand = get_brand_code_and_bits(data); + model_code = get_model_code(data); + for (i = 0; i < COUNT_OF(intel_bcode_str); i++) { + if (brand.code == intel_bcode_str[i].code) { + brand_code_str = intel_bcode_str[i].str; + break; + } + } + if (brand_code_str) + debugf(2, "Detected Intel brand code: %d (%s)\n", brand.code, brand_code_str); + else + debugf(2, "Detected Intel brand code: %d\n", brand.code); + if (brand.bits) { + debugf(2, "Detected Intel bits: "); + debug_print_lbits(2, brand.bits); + } + debugf(2, "Detected Intel model code: %d\n", model_code); internal->code.intel = brand.code; internal->bits = brand.bits; if (data->flags[CPU_FEATURE_SGX]) { + debugf(2, "SGX seems to be present, decoding...\n"); // if SGX is indicated by the CPU, verify its presence: decode_intel_sgx_features(raw, data); } + internal->score = match_cpu_codename(cpudb_intel, COUNT_OF(cpudb_intel), data, + brand.code, brand.bits, model_code); return 0; } + +void cpuid_get_list_intel(struct cpu_list_t* list) +{ + generic_get_cpu_list(cpudb_intel, COUNT_OF(cpudb_intel), list); +} diff --git a/src/3rdparty/libcpuid/recog_intel.h b/src/3rdparty/libcpuid/recog_intel.h index 96676f3b..b99c783b 100644 --- a/src/3rdparty/libcpuid/recog_intel.h +++ b/src/3rdparty/libcpuid/recog_intel.h @@ -27,5 +27,6 @@ #define __RECOG_INTEL_H__ int cpuid_identify_intel(struct cpu_raw_data_t* raw, struct cpu_id_t* data, struct internal_id_info_t* internal); +void cpuid_get_list_intel(struct cpu_list_t* list); #endif /*__RECOG_INTEL_H__*/ diff --git a/src/3rdparty/rapidjson/allocators.h b/src/3rdparty/rapidjson/allocators.h index 98affe03..655f4a38 100644 --- a/src/3rdparty/rapidjson/allocators.h +++ b/src/3rdparty/rapidjson/allocators.h @@ -236,7 +236,7 @@ private: */ bool AddChunk(size_t capacity) { if (!baseAllocator_) - ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator()); + ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)(); if (ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) { chunk->capacity = capacity; chunk->size = 0; diff --git a/src/3rdparty/rapidjson/cursorstreamwrapper.h b/src/3rdparty/rapidjson/cursorstreamwrapper.h new file mode 100644 index 00000000..52c11a7c --- /dev/null +++ b/src/3rdparty/rapidjson/cursorstreamwrapper.h @@ -0,0 +1,78 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_CURSORSTREAMWRAPPER_H_ +#define RAPIDJSON_CURSORSTREAMWRAPPER_H_ + +#include "stream.h" + +#if defined(__GNUC__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4702) // unreachable code +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + + +//! Cursor stream wrapper for counting line and column number if error exists. +/*! + \tparam InputStream Any stream that implements Stream Concept +*/ +template > +class CursorStreamWrapper : public GenericStreamWrapper { +public: + typedef typename Encoding::Ch Ch; + + CursorStreamWrapper(InputStream& is): + GenericStreamWrapper(is), line_(1), col_(0) {} + + // counting line and column number + Ch Take() { + Ch ch = this->is_.Take(); + if(ch == '\n') { + line_ ++; + col_ = 0; + } else { + col_ ++; + } + return ch; + } + + //! Get the error line number, if error exists. + size_t GetLine() const { return line_; } + //! Get the error column number, if error exists. + size_t GetColumn() const { return col_; } + +private: + size_t line_; //!< Current Line + size_t col_; //!< Current Column +}; + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_POP +#endif + +#if defined(__GNUC__) +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_CURSORSTREAMWRAPPER_H_ diff --git a/src/3rdparty/rapidjson/document.h b/src/3rdparty/rapidjson/document.h index e3e20dfb..eb6d7dcb 100644 --- a/src/3rdparty/rapidjson/document.h +++ b/src/3rdparty/rapidjson/document.h @@ -45,7 +45,7 @@ RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_N #endif // __GNUC__ #ifndef RAPIDJSON_NOMEMBERITERATORCLASS -#include // std::iterator, std::random_access_iterator_tag +#include // std::random_access_iterator_tag #endif #if RAPIDJSON_HAS_CXX11_RVALUE_REFS @@ -98,16 +98,13 @@ struct GenericMember { \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator */ template -class GenericMemberIterator - : public std::iterator >::Type> { +class GenericMemberIterator { friend class GenericValue; template friend class GenericMemberIterator; typedef GenericMember PlainType; typedef typename internal::MaybeAddConst::Type ValueType; - typedef std::iterator BaseType; public: //! Iterator type itself @@ -117,12 +114,21 @@ public: //! Non-constant iterator type typedef GenericMemberIterator NonConstIterator; + /** \name std::iterator_traits support */ + //@{ + typedef ValueType value_type; + typedef ValueType * pointer; + typedef ValueType & reference; + typedef std::ptrdiff_t difference_type; + typedef std::random_access_iterator_tag iterator_category; + //@} + //! Pointer to (const) GenericMember - typedef typename BaseType::pointer Pointer; + typedef pointer Pointer; //! Reference to (const) GenericMember - typedef typename BaseType::reference Reference; + typedef reference Reference; //! Signed integer type (e.g. \c ptrdiff_t) - typedef typename BaseType::difference_type DifferenceType; + typedef difference_type DifferenceType; //! Default constructor (singular value) /*! Creates an iterator pointing to no element. @@ -300,7 +306,7 @@ struct GenericStringRef { */ #endif explicit GenericStringRef(const CharType* str) - : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != 0); } + : s(str), length(NotNullStrLen(str)) {} //! Create constant string reference from pointer and length #ifndef __clang__ // -Wdocumentation @@ -312,12 +318,10 @@ struct GenericStringRef { */ #endif GenericStringRef(const CharType* str, SizeType len) - : s(str), length(len) { RAPIDJSON_ASSERT(s != 0); } + : s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); } GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {} - GenericStringRef& operator=(const GenericStringRef& rhs) { s = rhs.s; length = rhs.length; } - //! implicit conversion to plain CharType pointer operator const Ch *() const { return s; } @@ -325,11 +329,24 @@ struct GenericStringRef { const SizeType length; //!< length of the string (excluding the trailing NULL terminator) private: + SizeType NotNullStrLen(const CharType* str) { + RAPIDJSON_ASSERT(str != 0); + return internal::StrLen(str); + } + + /// Empty string - used when passing in a NULL pointer + static const Ch emptyString[]; + //! Disallow construction from non-const array template GenericStringRef(CharType (&str)[N]) /* = delete */; + //! Copy assignment operator not permitted - immutable type + GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */; }; +template +const CharType GenericStringRef::emptyString[] = { CharType() }; + //! Mark a character pointer as constant string /*! Mark a plain character pointer as a "string literal". This function can be used to avoid copying a character string to be referenced as a @@ -344,7 +361,7 @@ private: */ template inline GenericStringRef StringRef(const CharType* str) { - return GenericStringRef(str, internal::StrLen(str)); + return GenericStringRef(str); } //! Mark a character pointer as constant string @@ -507,7 +524,7 @@ struct TypeHelper { static bool Is(const ValueType& v) { return v.IsObject(); } static ObjectType Get(ValueType& v) { return v.GetObject(); } static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } - static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { v = data; } + static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; } }; template @@ -594,7 +611,7 @@ public: kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, kNumberAnyFlag }; - RAPIDJSON_ASSERT(type <= kNumberType); + RAPIDJSON_ASSERT(type >= kNullType && type <= kNumberType); data_.f.flags = defaultFlags[type]; // Use ShortString to store empty string. @@ -607,10 +624,50 @@ public: \tparam SourceAllocator allocator of \c rhs \param rhs Value to copy from (read-only) \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). + \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) \see CopyFrom() */ - template< typename SourceAllocator > - GenericValue(const GenericValue& rhs, Allocator & allocator); + template + GenericValue(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { + switch (rhs.GetType()) { + case kObjectType: { + SizeType count = rhs.data_.o.size; + Member* lm = reinterpret_cast(allocator.Malloc(count * sizeof(Member))); + const typename GenericValue::Member* rm = rhs.GetMembersPointer(); + for (SizeType i = 0; i < count; i++) { + new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings); + new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings); + } + data_.f.flags = kObjectFlag; + data_.o.size = data_.o.capacity = count; + SetMembersPointer(lm); + } + break; + case kArrayType: { + SizeType count = rhs.data_.a.size; + GenericValue* le = reinterpret_cast(allocator.Malloc(count * sizeof(GenericValue))); + const GenericValue* re = rhs.GetElementsPointer(); + for (SizeType i = 0; i < count; i++) + new (&le[i]) GenericValue(re[i], allocator, copyConstStrings); + data_.f.flags = kArrayFlag; + data_.a.size = data_.a.capacity = count; + SetElementsPointer(le); + } + break; + case kStringType: + if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) { + data_.f.flags = rhs.data_.f.flags; + data_ = *reinterpret_cast(&rhs.data_); + } + else + SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); + break; + default: + data_.f.flags = rhs.data_.f.flags; + data_ = *reinterpret_cast(&rhs.data_); + break; + } + } //! Constructor for boolean value. /*! \param b Boolean value @@ -672,6 +729,9 @@ public: //! Constructor for double value. explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; } + //! Constructor for float value. + explicit GenericValue(float f) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = static_cast(f); data_.f.flags = kNumberDoubleFlag; } + //! Constructor for constant string (i.e. do not make a copy of string) GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); } @@ -800,12 +860,13 @@ public: \tparam SourceAllocator Allocator type of \c rhs \param rhs Value to copy from (read-only) \param allocator Allocator to use for copying + \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) */ template - GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator) { + GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs)); this->~GenericValue(); - new (this) GenericValue(rhs, allocator); + new (this) GenericValue(rhs, allocator, copyConstStrings); return *this; } @@ -955,14 +1016,14 @@ public: uint64_t u = GetUint64(); volatile double d = static_cast(u); return (d >= 0.0) - && (d < static_cast(std::numeric_limits::max())) + && (d < static_cast((std::numeric_limits::max)())) && (u == static_cast(d)); } if (IsInt64()) { int64_t i = GetInt64(); volatile double d = static_cast(i); - return (d >= static_cast(std::numeric_limits::min())) - && (d < static_cast(std::numeric_limits::max())) + return (d >= static_cast((std::numeric_limits::min)())) + && (d < static_cast((std::numeric_limits::max)())) && (i == static_cast(d)); } return true; // double, int, uint are always lossless @@ -979,8 +1040,8 @@ public: bool IsLosslessFloat() const { if (!IsNumber()) return false; double a = GetDouble(); - if (a < static_cast(-std::numeric_limits::max()) - || a > static_cast(std::numeric_limits::max())) + if (a < static_cast(-(std::numeric_limits::max)()) + || a > static_cast((std::numeric_limits::max)())) return false; double b = static_cast(static_cast(a)); return a >= b && a <= b; // Prevent -Wfloat-equal @@ -1015,6 +1076,9 @@ public: //! Get the number of members in the object. SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } + //! Get the capacity of object. + SizeType MemberCapacity() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.capacity; } + //! Check whether the object is empty. bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } @@ -1083,6 +1147,21 @@ public: /*! \pre IsObject() == true */ MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); } + //! Request the object to have enough capacity to store members. + /*! \param newCapacity The capacity that the object at least need to have. + \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \note Linear time complexity. + */ + GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) { + RAPIDJSON_ASSERT(IsObject()); + if (newCapacity > data_.o.capacity) { + SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member)))); + data_.o.capacity = newCapacity; + } + return *this; + } + //! Check whether a member exists in the object. /*! \param name Member name to be searched. @@ -1188,17 +1267,8 @@ public: RAPIDJSON_ASSERT(name.IsString()); ObjectData& o = data_.o; - if (o.size >= o.capacity) { - if (o.capacity == 0) { - o.capacity = kDefaultObjectCapacity; - SetMembersPointer(reinterpret_cast(allocator.Malloc(o.capacity * sizeof(Member)))); - } - else { - SizeType oldCapacity = o.capacity; - o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5 - SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member)))); - } - } + if (o.size >= o.capacity) + MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator); Member* members = GetMembersPointer(); members[o.size].name.RawAssign(name); members[o.size].value.RawAssign(value); @@ -1671,7 +1741,7 @@ public: GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } - GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(f); return *this; } + GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(static_cast(f)); return *this; } //@} @@ -1710,7 +1780,7 @@ public: \return The value itself for fluent API. \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ - GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; } + GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); } //! Set this value as a string by copying from source string. /*! \param s source string. @@ -1718,7 +1788,15 @@ public: \return The value itself for fluent API. \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ - GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); } + GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); } + + //! Set this value as a string by copying from source string. + /*! \param s source string reference + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; } #if RAPIDJSON_HAS_STDSTRING //! Set this value as a string by copying from source string. @@ -1728,7 +1806,7 @@ public: \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ - GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); } + GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(StringRef(s), allocator); } #endif //@} @@ -2038,7 +2116,7 @@ public: GenericValue(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() { if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); } //! Constructor @@ -2051,7 +2129,7 @@ public: allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() { if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS @@ -2112,6 +2190,10 @@ public: return *this; } + // Allow Swap with ValueType. + // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names. + using ValueType::Swap; + //! free-standing swap function helper /*! Helper function to enable support for common swap implementation pattern based on \c std::swap: @@ -2243,7 +2325,7 @@ public: template GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) { RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); - MemoryStream ms(static_cast(str), length * sizeof(typename SourceEncoding::Ch)); + MemoryStream ms(reinterpret_cast(str), length * sizeof(typename SourceEncoding::Ch)); EncodedInputStream is(ms); ParseStream(is); return *this; @@ -2401,35 +2483,6 @@ private: //! GenericDocument with UTF8 encoding typedef GenericDocument > Document; -// defined here due to the dependency on GenericDocument -template -template -inline -GenericValue::GenericValue(const GenericValue& rhs, Allocator& allocator) -{ - switch (rhs.GetType()) { - case kObjectType: - case kArrayType: { // perform deep copy via SAX Handler - GenericDocument d(&allocator); - rhs.Accept(d); - RawAssign(*d.stack_.template Pop(1)); - } - break; - case kStringType: - if (rhs.data_.f.flags == kConstStringFlag) { - data_.f.flags = rhs.data_.f.flags; - data_ = *reinterpret_cast(&rhs.data_); - } else { - SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); - } - break; - default: - data_.f.flags = rhs.data_.f.flags; - data_ = *reinterpret_cast(&rhs.data_); - break; - } -} - //! Helper class for accessing Value of array type. /*! Instance of this helper class is obtained by \c GenericValue::GetArray(). @@ -2510,6 +2563,7 @@ public: ~GenericObject() {} SizeType MemberCount() const { return value_.MemberCount(); } + SizeType MemberCapacity() const { return value_.MemberCapacity(); } bool ObjectEmpty() const { return value_.ObjectEmpty(); } template ValueType& operator[](T* name) const { return value_[name]; } template ValueType& operator[](const GenericValue& name) const { return value_[name]; } @@ -2518,6 +2572,7 @@ public: #endif MemberIterator MemberBegin() const { return value_.MemberBegin(); } MemberIterator MemberEnd() const { return value_.MemberEnd(); } + GenericObject MemberReserve(SizeType newCapacity, AllocatorType &allocator) const { value_.MemberReserve(newCapacity, allocator); return *this; } bool HasMember(const Ch* name) const { return value_.HasMember(name); } #if RAPIDJSON_HAS_STDSTRING bool HasMember(const std::basic_string& name) const { return value_.HasMember(name); } @@ -2543,7 +2598,7 @@ public: GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } - void RemoveAllMembers() { return value_.RemoveAllMembers(); } + void RemoveAllMembers() { value_.RemoveAllMembers(); } bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); } #if RAPIDJSON_HAS_STDSTRING bool RemoveMember(const std::basic_string& name) const { return value_.RemoveMember(name); } diff --git a/src/3rdparty/rapidjson/encodedstream.h b/src/3rdparty/rapidjson/encodedstream.h index 14506838..223601c0 100644 --- a/src/3rdparty/rapidjson/encodedstream.h +++ b/src/3rdparty/rapidjson/encodedstream.h @@ -200,7 +200,7 @@ private: // xx xx xx xx UTF-8 if (!hasBOM_) { - unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); + int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); switch (pattern) { case 0x08: type_ = kUTF32BE; break; case 0x0A: type_ = kUTF16BE; break; diff --git a/src/3rdparty/rapidjson/encodings.h b/src/3rdparty/rapidjson/encodings.h index baa7c2b1..7903e76a 100644 --- a/src/3rdparty/rapidjson/encodings.h +++ b/src/3rdparty/rapidjson/encodings.h @@ -157,7 +157,7 @@ struct UTF8 { if (type >= 32) { *codepoint = 0; } else { - *codepoint = (0xFF >> type) & static_cast(c); + *codepoint = (0xFFu >> type) & static_cast(c); } bool result = true; switch (type) { @@ -283,7 +283,7 @@ struct UTF16 { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); unsigned v = codepoint - 0x10000; os.Put(static_cast((v >> 10) | 0xD800)); - os.Put((v & 0x3FF) | 0xDC00); + os.Put(static_cast((v & 0x3FF) | 0xDC00)); } } @@ -299,7 +299,7 @@ struct UTF16 { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); unsigned v = codepoint - 0x10000; PutUnsafe(os, static_cast((v >> 10) | 0xD800)); - PutUnsafe(os, (v & 0x3FF) | 0xDC00); + PutUnsafe(os, static_cast((v & 0x3FF) | 0xDC00)); } } @@ -384,7 +384,7 @@ struct UTF16BE : UTF16 { static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); unsigned c = static_cast(static_cast(is.Take())) << 8; - c |= static_cast(is.Take()); + c |= static_cast(static_cast(is.Take())); return static_cast(c); } @@ -620,28 +620,28 @@ struct AutoUTF { #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x template - RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) { + static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) { typedef void (*EncodeFunc)(OutputStream&, unsigned); static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; (*f[os.GetType()])(os, codepoint); } template - RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) { typedef void (*EncodeFunc)(OutputStream&, unsigned); static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; (*f[os.GetType()])(os, codepoint); } template - RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { + static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) { typedef bool (*DecodeFunc)(InputStream&, unsigned*); static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; return (*f[is.GetType()])(is, codepoint); } template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { typedef bool (*ValidateFunc)(InputStream&, OutputStream&); static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; return (*f[is.GetType()])(is, os); @@ -658,7 +658,7 @@ template struct Transcoder { //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. template - RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; @@ -667,7 +667,7 @@ struct Transcoder { } template - RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; @@ -677,7 +677,7 @@ struct Transcoder { //! Validate one Unicode codepoint from an encoded stream. template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { return Transcode(is, os); // Since source/target encoding is different, must transcode. } }; @@ -690,19 +690,19 @@ inline void PutUnsafe(Stream& stream, typename Stream::Ch c); template struct Transcoder { template - RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. return true; } template - RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class. return true; } template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { return Encoding::Validate(is, os); // source/target encoding are the same } }; diff --git a/src/3rdparty/rapidjson/error/error.h b/src/3rdparty/rapidjson/error/error.h index 95cb31a7..9311d2f0 100644 --- a/src/3rdparty/rapidjson/error/error.h +++ b/src/3rdparty/rapidjson/error/error.h @@ -104,6 +104,8 @@ enum ParseErrorCode { \see GenericReader::Parse, GenericDocument::Parse */ struct ParseResult { + //!! Unspecified boolean type + typedef bool (ParseResult::*BooleanType)() const; public: //! Default constructor, no error. ParseResult() : code_(kParseErrorNone), offset_(0) {} @@ -115,8 +117,8 @@ public: //! Get the error offset, if \ref IsError(), 0 otherwise. size_t Offset() const { return offset_; } - //! Conversion to \c bool, returns \c true, iff !\ref IsError(). - operator bool() const { return !IsError(); } + //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError(). + operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; } //! Whether the result is an error. bool IsError() const { return code_ != kParseErrorNone; } @@ -124,6 +126,10 @@ public: bool operator==(ParseErrorCode code) const { return code_ == code; } friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } + bool operator!=(const ParseResult& that) const { return !(*this == that); } + bool operator!=(ParseErrorCode code) const { return !(*this == code); } + friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; } + //! Reset error code. void Clear() { Set(kParseErrorNone); } //! Update error code and offset. diff --git a/src/3rdparty/rapidjson/filereadstream.h b/src/3rdparty/rapidjson/filereadstream.h index b56ea13b..f1bfb7d0 100644 --- a/src/3rdparty/rapidjson/filereadstream.h +++ b/src/3rdparty/rapidjson/filereadstream.h @@ -68,7 +68,7 @@ private: ++current_; else if (!eof_) { count_ += readCount_; - readCount_ = fread(buffer_, 1, bufferSize_, fp_); + readCount_ = std::fread(buffer_, 1, bufferSize_, fp_); bufferLast_ = buffer_ + readCount_ - 1; current_ = buffer_; diff --git a/src/3rdparty/rapidjson/filewritestream.h b/src/3rdparty/rapidjson/filewritestream.h index 6378dd60..3811f8b8 100644 --- a/src/3rdparty/rapidjson/filewritestream.h +++ b/src/3rdparty/rapidjson/filewritestream.h @@ -62,7 +62,7 @@ public: void Flush() { if (current_ != buffer_) { - size_t result = fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); + size_t result = std::fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); if (result < static_cast(current_ - buffer_)) { // failure deliberately ignored at this time // added to avoid warn_unused_result build errors diff --git a/src/3rdparty/rapidjson/internal/diyfp.h b/src/3rdparty/rapidjson/internal/diyfp.h index c9fefdc6..29abf804 100644 --- a/src/3rdparty/rapidjson/internal/diyfp.h +++ b/src/3rdparty/rapidjson/internal/diyfp.h @@ -21,7 +21,7 @@ #include "../rapidjson.h" -#if defined(_MSC_VER) && defined(_M_AMD64) +#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) #include #pragma intrinsic(_BitScanReverse64) #pragma intrinsic(_umul128) diff --git a/src/3rdparty/rapidjson/internal/dtoa.h b/src/3rdparty/rapidjson/internal/dtoa.h index 8d6350e6..bf2e9b2e 100644 --- a/src/3rdparty/rapidjson/internal/dtoa.h +++ b/src/3rdparty/rapidjson/internal/dtoa.h @@ -41,7 +41,7 @@ inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uin } } -inline unsigned CountDecimalDigit32(uint32_t n) { +inline int CountDecimalDigit32(uint32_t n) { // Simple pure C++ implementation was faster than __builtin_clz version in this situation. if (n < 10) return 1; if (n < 100) return 2; @@ -63,7 +63,7 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff const DiyFp wp_w = Mp - W; uint32_t p1 = static_cast(Mp.f >> -one.e); uint64_t p2 = Mp.f & (one.f - 1); - unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9] + int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] *len = 0; while (kappa > 0) { @@ -102,8 +102,8 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff kappa--; if (p2 < delta) { *K += kappa; - int index = -static_cast(kappa); - GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast(kappa)] : 0)); + int index = -kappa; + GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0)); return; } } diff --git a/src/3rdparty/rapidjson/internal/ieee754.h b/src/3rdparty/rapidjson/internal/ieee754.h index 82bb0b99..c2684ba2 100644 --- a/src/3rdparty/rapidjson/internal/ieee754.h +++ b/src/3rdparty/rapidjson/internal/ieee754.h @@ -48,13 +48,13 @@ public: int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } - static unsigned EffectiveSignificandSize(int order) { + static int EffectiveSignificandSize(int order) { if (order >= -1021) return 53; else if (order <= -1074) return 0; else - return static_cast(order) + 1074; + return order + 1074; } private: diff --git a/src/3rdparty/rapidjson/internal/regex.h b/src/3rdparty/rapidjson/internal/regex.h index 422a5240..e1a2faae 100644 --- a/src/3rdparty/rapidjson/internal/regex.h +++ b/src/3rdparty/rapidjson/internal/regex.h @@ -29,6 +29,9 @@ RAPIDJSON_DIAG_OFF(implicit-fallthrough) #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) +#if __GNUC__ >= 7 +RAPIDJSON_DIAG_OFF(implicit-fallthrough) +#endif #endif #ifdef _MSC_VER @@ -43,12 +46,40 @@ RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated RAPIDJSON_NAMESPACE_BEGIN namespace internal { +/////////////////////////////////////////////////////////////////////////////// +// DecodedStream + +template +class DecodedStream { +public: + DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); } + unsigned Peek() { return codepoint_; } + unsigned Take() { + unsigned c = codepoint_; + if (c) // No further decoding when '\0' + Decode(); + return c; + } + +private: + void Decode() { + if (!Encoding::Decode(ss_, &codepoint_)) + codepoint_ = 0; + } + + SourceStream& ss_; + unsigned codepoint_; +}; + /////////////////////////////////////////////////////////////////////////////// // GenericRegex static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1 static const SizeType kRegexInvalidRange = ~SizeType(0); +template +class GenericRegexSearch; + //! Regular expression engine with subset of ECMAscript grammar. /*! Supported regular expression syntax: @@ -84,45 +115,25 @@ static const SizeType kRegexInvalidRange = ~SizeType(0); template class GenericRegex { public: + typedef Encoding EncodingType; typedef typename Encoding::Ch Ch; + template friend class GenericRegexSearch; GenericRegex(const Ch* source, Allocator* allocator = 0) : states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), - stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_() + anchorBegin_(), anchorEnd_() { GenericStringStream ss(source); - DecodedStream > ds(ss); + DecodedStream, Encoding> ds(ss); Parse(ds); } - ~GenericRegex() { - Allocator::Free(stateSet_); - } + ~GenericRegex() {} bool IsValid() const { return root_ != kRegexInvalidState; } - template - bool Match(InputStream& is) const { - return SearchWithAnchoring(is, true, true); - } - - bool Match(const Ch* s) const { - GenericStringStream is(s); - return Match(is); - } - - template - bool Search(InputStream& is) const { - return SearchWithAnchoring(is, anchorBegin_, anchorEnd_); - } - - bool Search(const Ch* s) const { - GenericStringStream is(s); - return Search(is); - } - private: enum Operator { kZeroOrOne, @@ -157,28 +168,6 @@ private: SizeType minIndex; }; - template - class DecodedStream { - public: - DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); } - unsigned Peek() { return codepoint_; } - unsigned Take() { - unsigned c = codepoint_; - if (c) // No further decoding when '\0' - Decode(); - return c; - } - - private: - void Decode() { - if (!Encoding::Decode(ss_, &codepoint_)) - codepoint_ = 0; - } - - SourceStream& ss_; - unsigned codepoint_; - }; - State& GetState(SizeType index) { RAPIDJSON_ASSERT(index < stateCount_); return states_.template Bottom()[index]; @@ -200,7 +189,7 @@ private: } template - void Parse(DecodedStream& ds) { + void Parse(DecodedStream& ds) { Allocator allocator; Stack operandStack(&allocator, 256); // Frag Stack operatorStack(&allocator, 256); // Operator @@ -327,14 +316,6 @@ private: printf("\n"); #endif } - - // Preallocate buffer for SearchWithAnchoring() - RAPIDJSON_ASSERT(stateSet_ == 0); - if (stateCount_ > 0) { - stateSet_ = static_cast(states_.GetAllocator().Malloc(GetStateSetSize())); - state0_.template Reserve(stateCount_); - state1_.template Reserve(stateCount_); - } } SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) { @@ -483,7 +464,7 @@ private: } template - bool ParseUnsigned(DecodedStream& ds, unsigned* u) { + bool ParseUnsigned(DecodedStream& ds, unsigned* u) { unsigned r = 0; if (ds.Peek() < '0' || ds.Peek() > '9') return false; @@ -497,7 +478,7 @@ private: } template - bool ParseRange(DecodedStream& ds, SizeType* range) { + bool ParseRange(DecodedStream& ds, SizeType* range) { bool isBegin = true; bool negate = false; int step = 0; @@ -575,7 +556,7 @@ private: } template - bool CharacterEscape(DecodedStream& ds, unsigned* escapedCodepoint) { + bool CharacterEscape(DecodedStream& ds, unsigned* escapedCodepoint) { unsigned codepoint; switch (codepoint = ds.Take()) { case '^': @@ -603,72 +584,6 @@ private: } } - template - bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const { - RAPIDJSON_ASSERT(IsValid()); - DecodedStream ds(is); - - state0_.Clear(); - Stack *current = &state0_, *next = &state1_; - const size_t stateSetSize = GetStateSetSize(); - std::memset(stateSet_, 0, stateSetSize); - - bool matched = AddState(*current, root_); - unsigned codepoint; - while (!current->Empty() && (codepoint = ds.Take()) != 0) { - std::memset(stateSet_, 0, stateSetSize); - next->Clear(); - matched = false; - for (const SizeType* s = current->template Bottom(); s != current->template End(); ++s) { - const State& sr = GetState(*s); - if (sr.codepoint == codepoint || - sr.codepoint == kAnyCharacterClass || - (sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) - { - matched = AddState(*next, sr.out) || matched; - if (!anchorEnd && matched) - return true; - } - if (!anchorBegin) - AddState(*next, root_); - } - internal::Swap(current, next); - } - - return matched; - } - - size_t GetStateSetSize() const { - return (stateCount_ + 31) / 32 * 4; - } - - // Return whether the added states is a match state - bool AddState(Stack& l, SizeType index) const { - RAPIDJSON_ASSERT(index != kRegexInvalidState); - - const State& s = GetState(index); - if (s.out1 != kRegexInvalidState) { // Split - bool matched = AddState(l, s.out); - return AddState(l, s.out1) || matched; - } - else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) { - stateSet_[index >> 5] |= (1 << (index & 31)); - *l.template PushUnsafe() = index; - } - return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation. - } - - bool MatchRange(SizeType rangeIndex, unsigned codepoint) const { - bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0; - while (rangeIndex != kRegexInvalidRange) { - const Range& r = GetRange(rangeIndex); - if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end) - return yes; - rangeIndex = r.next; - } - return !yes; - } - Stack states_; Stack ranges_; SizeType root_; @@ -678,14 +593,132 @@ private: static const unsigned kInfinityQuantifier = ~0u; // For SearchWithAnchoring() - uint32_t* stateSet_; // allocated by states_.GetAllocator() - mutable Stack state0_; - mutable Stack state1_; bool anchorBegin_; bool anchorEnd_; }; +template +class GenericRegexSearch { +public: + typedef typename RegexType::EncodingType Encoding; + typedef typename Encoding::Ch Ch; + + GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) : + regex_(regex), allocator_(allocator), ownAllocator_(0), + state0_(allocator, 0), state1_(allocator, 0), stateSet_() + { + RAPIDJSON_ASSERT(regex_.IsValid()); + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + stateSet_ = static_cast(allocator_->Malloc(GetStateSetSize())); + state0_.template Reserve(regex_.stateCount_); + state1_.template Reserve(regex_.stateCount_); + } + + ~GenericRegexSearch() { + Allocator::Free(stateSet_); + RAPIDJSON_DELETE(ownAllocator_); + } + + template + bool Match(InputStream& is) { + return SearchWithAnchoring(is, true, true); + } + + bool Match(const Ch* s) { + GenericStringStream is(s); + return Match(is); + } + + template + bool Search(InputStream& is) { + return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_); + } + + bool Search(const Ch* s) { + GenericStringStream is(s); + return Search(is); + } + +private: + typedef typename RegexType::State State; + typedef typename RegexType::Range Range; + + template + bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) { + DecodedStream ds(is); + + state0_.Clear(); + Stack *current = &state0_, *next = &state1_; + const size_t stateSetSize = GetStateSetSize(); + std::memset(stateSet_, 0, stateSetSize); + + bool matched = AddState(*current, regex_.root_); + unsigned codepoint; + while (!current->Empty() && (codepoint = ds.Take()) != 0) { + std::memset(stateSet_, 0, stateSetSize); + next->Clear(); + matched = false; + for (const SizeType* s = current->template Bottom(); s != current->template End(); ++s) { + const State& sr = regex_.GetState(*s); + if (sr.codepoint == codepoint || + sr.codepoint == RegexType::kAnyCharacterClass || + (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) + { + matched = AddState(*next, sr.out) || matched; + if (!anchorEnd && matched) + return true; + } + if (!anchorBegin) + AddState(*next, regex_.root_); + } + internal::Swap(current, next); + } + + return matched; + } + + size_t GetStateSetSize() const { + return (regex_.stateCount_ + 31) / 32 * 4; + } + + // Return whether the added states is a match state + bool AddState(Stack& l, SizeType index) { + RAPIDJSON_ASSERT(index != kRegexInvalidState); + + const State& s = regex_.GetState(index); + if (s.out1 != kRegexInvalidState) { // Split + bool matched = AddState(l, s.out); + return AddState(l, s.out1) || matched; + } + else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) { + stateSet_[index >> 5] |= (1u << (index & 31)); + *l.template PushUnsafe() = index; + } + return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation. + } + + bool MatchRange(SizeType rangeIndex, unsigned codepoint) const { + bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0; + while (rangeIndex != kRegexInvalidRange) { + const Range& r = regex_.GetRange(rangeIndex); + if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end) + return yes; + rangeIndex = r.next; + } + return !yes; + } + + const RegexType& regex_; + Allocator* allocator_; + Allocator* ownAllocator_; + Stack state0_; + Stack state1_; + uint32_t* stateSet_; +}; + typedef GenericRegex > Regex; +typedef GenericRegexSearch RegexSearch; } // namespace internal RAPIDJSON_NAMESPACE_END diff --git a/src/3rdparty/rapidjson/internal/stack.h b/src/3rdparty/rapidjson/internal/stack.h index 022c9aab..5c5398c3 100644 --- a/src/3rdparty/rapidjson/internal/stack.h +++ b/src/3rdparty/rapidjson/internal/stack.h @@ -126,6 +126,7 @@ public: template RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { + RAPIDJSON_ASSERT(stackTop_); RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_); T* ret = reinterpret_cast(stackTop_); stackTop_ += sizeof(T) * count; @@ -183,7 +184,7 @@ private: size_t newCapacity; if (stack_ == 0) { if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); newCapacity = initialCapacity_; } else { newCapacity = GetCapacity(); diff --git a/src/3rdparty/rapidjson/internal/strfunc.h b/src/3rdparty/rapidjson/internal/strfunc.h index 2edfae52..226439a7 100644 --- a/src/3rdparty/rapidjson/internal/strfunc.h +++ b/src/3rdparty/rapidjson/internal/strfunc.h @@ -16,6 +16,7 @@ #define RAPIDJSON_INTERNAL_STRFUNC_H_ #include "../stream.h" +#include RAPIDJSON_NAMESPACE_BEGIN namespace internal { @@ -28,14 +29,27 @@ namespace internal { */ template inline SizeType StrLen(const Ch* s) { + RAPIDJSON_ASSERT(s != 0); const Ch* p = s; while (*p) ++p; return SizeType(p - s); } +template <> +inline SizeType StrLen(const char* s) { + return SizeType(std::strlen(s)); +} + +template <> +inline SizeType StrLen(const wchar_t* s) { + return SizeType(std::wcslen(s)); +} + //! Returns number of code points in a encoded string. template bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { + RAPIDJSON_ASSERT(s != 0); + RAPIDJSON_ASSERT(outCount != 0); GenericStringStream is(s); const typename Encoding::Ch* end = s + length; SizeType count = 0; diff --git a/src/3rdparty/rapidjson/internal/strtod.h b/src/3rdparty/rapidjson/internal/strtod.h index 289c413b..adf49e34 100644 --- a/src/3rdparty/rapidjson/internal/strtod.h +++ b/src/3rdparty/rapidjson/internal/strtod.h @@ -140,8 +140,8 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit significand++; size_t remaining = length - i; - const unsigned kUlpShift = 3; - const unsigned kUlp = 1 << kUlpShift; + const int kUlpShift = 3; + const int kUlp = 1 << kUlpShift; int64_t error = (remaining == 0) ? 0 : kUlp / 2; DiyFp v(significand, 0); @@ -177,17 +177,17 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit v = v.Normalize(); error <<= oldExp - v.e; - const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); - unsigned precisionSize = 64 - effectiveSignificandSize; + const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); + int precisionSize = 64 - effectiveSignificandSize; if (precisionSize + kUlpShift >= 64) { - unsigned scaleExp = (precisionSize + kUlpShift) - 63; + int scaleExp = (precisionSize + kUlpShift) - 63; v.f >>= scaleExp; v.e += scaleExp; - error = (error >> scaleExp) + 1 + static_cast(kUlp); + error = (error >> scaleExp) + 1 + kUlp; precisionSize -= scaleExp; } - DiyFp rounded(v.f >> precisionSize, v.e + static_cast(precisionSize)); + DiyFp rounded(v.f >> precisionSize, v.e + precisionSize); const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; if (precisionBits >= halfWay + static_cast(error)) { diff --git a/src/3rdparty/rapidjson/istreamwrapper.h b/src/3rdparty/rapidjson/istreamwrapper.h index f5fe2897..8639c8c3 100644 --- a/src/3rdparty/rapidjson/istreamwrapper.h +++ b/src/3rdparty/rapidjson/istreamwrapper.h @@ -54,7 +54,7 @@ public: Ch Peek() const { typename StreamType::int_type c = stream_.peek(); - return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast(c) : '\0'; + return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast(c) : static_cast('\0'); } Ch Take() { diff --git a/src/3rdparty/rapidjson/pointer.h b/src/3rdparty/rapidjson/pointer.h index 0206ac1c..0f377efe 100644 --- a/src/3rdparty/rapidjson/pointer.h +++ b/src/3rdparty/rapidjson/pointer.h @@ -240,7 +240,7 @@ public: template RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >), (GenericPointer)) Append(T* name, Allocator* allocator = 0) const { - return Append(name, StrLen(name), allocator); + return Append(name, internal::StrLen(name), allocator); } #if RAPIDJSON_HAS_STDSTRING @@ -274,7 +274,7 @@ public: else { Ch name[21]; for (size_t i = 0; i <= length; i++) - name[i] = buffer[i]; + name[i] = static_cast(buffer[i]); Token token = { name, length, index }; return Append(token, allocator); } @@ -758,7 +758,7 @@ private: */ Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) { if (!allocator_) // allocator is independently owned. - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) @@ -806,7 +806,7 @@ private: // Create own allocator if user did not supply. if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); // Count number of '/' as tokenCount tokenCount_ = 0; @@ -1029,8 +1029,8 @@ private: unsigned char u = static_cast(c); static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; os_.Put('%'); - os_.Put(hexDigits[u >> 4]); - os_.Put(hexDigits[u & 15]); + os_.Put(static_cast(hexDigits[u >> 4])); + os_.Put(static_cast(hexDigits[u & 15])); } private: OutputStream& os_; diff --git a/src/3rdparty/rapidjson/prettywriter.h b/src/3rdparty/rapidjson/prettywriter.h index 0dcb0fee..98dfb306 100644 --- a/src/3rdparty/rapidjson/prettywriter.h +++ b/src/3rdparty/rapidjson/prettywriter.h @@ -22,6 +22,11 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + RAPIDJSON_NAMESPACE_BEGIN //! Combination of PrettyWriter format flags. @@ -42,7 +47,7 @@ enum PrettyFormatOptions { template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> class PrettyWriter : public Writer { public: - typedef Writer Base; + typedef Writer Base; typedef typename Base::Ch Ch; //! Constructor @@ -57,6 +62,11 @@ public: explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + PrettyWriter(PrettyWriter&& rhs) : + Base(std::forward(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {} +#endif + //! Set custom indentation. /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). \param indentCharCount Number of indent characters for each indentation level. @@ -91,12 +101,14 @@ public: bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); } bool RawNumber(const Ch* str, SizeType length, bool copy = false) { + RAPIDJSON_ASSERT(str != 0); (void)copy; PrettyPrefix(kNumberType); return Base::WriteString(str, length); } bool String(const Ch* str, SizeType length, bool copy = false) { + RAPIDJSON_ASSERT(str != 0); (void)copy; PrettyPrefix(kStringType); return Base::WriteString(str, length); @@ -124,8 +136,10 @@ public: bool EndObject(SizeType memberCount = 0) { (void)memberCount; - RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); - RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object + RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); // currently inside an Array, not Object + RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; if (!empty) { @@ -136,7 +150,7 @@ public: (void)ret; RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text - Base::os_->Flush(); + Base::Flush(); return true; } @@ -160,7 +174,7 @@ public: (void)ret; RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text - Base::os_->Flush(); + Base::Flush(); return true; } @@ -184,7 +198,11 @@ public: \param type Type of the root of json. \note When using PrettyWriter::RawValue(), the result json may not be indented correctly. */ - bool RawValue(const Ch* json, size_t length, Type type) { PrettyPrefix(type); return Base::WriteRawValue(json, length); } + bool RawValue(const Ch* json, size_t length, Type type) { + RAPIDJSON_ASSERT(json != 0); + PrettyPrefix(type); + return Base::WriteRawValue(json, length); + } protected: void PrettyPrefix(Type type) { @@ -233,7 +251,7 @@ protected: void WriteIndent() { size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; - PutN(*Base::os_, static_cast(indentChar_), count); + PutN(*Base::os_, static_cast(indentChar_), count); } Ch indentChar_; @@ -248,6 +266,10 @@ private: RAPIDJSON_NAMESPACE_END +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif diff --git a/src/3rdparty/rapidjson/rapidjson.h b/src/3rdparty/rapidjson/rapidjson.h index 2ef9bc56..5716fdc0 100644 --- a/src/3rdparty/rapidjson/rapidjson.h +++ b/src/3rdparty/rapidjson/rapidjson.h @@ -49,6 +49,11 @@ // token stringification #define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) #define RAPIDJSON_DO_STRINGIFY(x) #x + +// token concatenation +#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) +#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) +#define RAPIDJSON_DO_JOIN2(X, Y) X##Y //!@endcond /*! \def RAPIDJSON_MAJOR_VERSION @@ -236,7 +241,7 @@ # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN -# elif defined(_MSC_VER) && defined(_M_ARM) +# elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(RAPIDJSON_DOXYGEN_RUNNING) # define RAPIDJSON_ENDIAN @@ -320,17 +325,17 @@ #endif /////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD +// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD /*! \def RAPIDJSON_SIMD \ingroup RAPIDJSON_CONFIG - \brief Enable SSE2/SSE4.2 optimization. + \brief Enable SSE2/SSE4.2/Neon optimization. RapidJSON supports optimized implementations for some parsing operations - based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible - processors. + based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel + or ARM compatible processors. - To enable these optimizations, two different symbols can be defined; + To enable these optimizations, three different symbols can be defined; \code // Enable SSE2 optimization. #define RAPIDJSON_SSE2 @@ -339,13 +344,17 @@ #define RAPIDJSON_SSE42 \endcode - \c RAPIDJSON_SSE42 takes precedence, if both are defined. + // Enable ARM Neon optimization. + #define RAPIDJSON_NEON + \endcode + + \c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined. If any of these symbols is defined, RapidJSON defines the macro \c RAPIDJSON_SIMD to indicate the availability of the optimized code. */ #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ - || defined(RAPIDJSON_DOXYGEN_RUNNING) + || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING) #define RAPIDJSON_SIMD #endif @@ -398,13 +407,22 @@ RAPIDJSON_NAMESPACE_END \ref RAPIDJSON_ERRORS APIs. */ #ifndef RAPIDJSON_ASSERT -#define RAPIDJSON_ASSERT(x) +#include +#define RAPIDJSON_ASSERT(x) assert(x) #endif // RAPIDJSON_ASSERT /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_STATIC_ASSERT -// Adopt from boost +// Prefer C++11 static_assert, if available +#ifndef RAPIDJSON_STATIC_ASSERT +#if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 ) +#define RAPIDJSON_STATIC_ASSERT(x) \ + static_assert(x, RAPIDJSON_STRINGIFY(x)) +#endif // C++11 +#endif // RAPIDJSON_STATIC_ASSERT + +// Adopt C++03 implementation from boost #ifndef RAPIDJSON_STATIC_ASSERT #ifndef __clang__ //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN @@ -412,13 +430,9 @@ RAPIDJSON_NAMESPACE_END RAPIDJSON_NAMESPACE_BEGIN template struct STATIC_ASSERTION_FAILURE; template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; -template struct StaticAssertTest {}; +template struct StaticAssertTest {}; RAPIDJSON_NAMESPACE_END -#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) -#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) -#define RAPIDJSON_DO_JOIN2(X, Y) X##Y - #if defined(__GNUC__) #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) #else @@ -437,7 +451,7 @@ RAPIDJSON_NAMESPACE_END typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE)> \ RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE -#endif +#endif // RAPIDJSON_STATIC_ASSERT /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY @@ -567,7 +581,7 @@ RAPIDJSON_NAMESPACE_END #ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR #if defined(__clang__) #define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) -#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ (defined(_MSC_VER) && _MSC_VER >= 1700) #define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 #else @@ -582,7 +596,7 @@ RAPIDJSON_NAMESPACE_END #ifndef RAPIDJSON_NEW ///! customization point for global \c new -#define RAPIDJSON_NEW(x) new x +#define RAPIDJSON_NEW(TypeName) new TypeName #endif #ifndef RAPIDJSON_DELETE ///! customization point for global \c delete diff --git a/src/3rdparty/rapidjson/reader.h b/src/3rdparty/rapidjson/reader.h index 303aac2e..681dec28 100644 --- a/src/3rdparty/rapidjson/reader.h +++ b/src/3rdparty/rapidjson/reader.h @@ -33,6 +33,8 @@ #include #elif defined(RAPIDJSON_SSE2) #include +#elif defined(RAPIDJSON_NEON) +#include #endif #ifdef _MSC_VER @@ -136,7 +138,7 @@ RAPIDJSON_NAMESPACE_BEGIN User can define this as any \c ParseFlag combinations. */ #ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS -#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseCommentsFlag | kParseTrailingCommasFlag +#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags #endif //! Combination of parseFlags @@ -299,16 +301,9 @@ inline const char *SkipWhitespace_SIMD(const char* p) { for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); - const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); - if (r != 0) { // some of characters is non-whitespace -#ifdef _MSC_VER // Find the index of first non-whitespace - unsigned long offset; - _BitScanForward(&offset, r); - return p + offset; -#else - return p + __builtin_ffs(r) - 1; -#endif - } + const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); + if (r != 16) // some of characters is non-whitespace + return p + r; } } @@ -325,16 +320,9 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { for (; p <= end - 16; p += 16) { const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); - const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); - if (r != 0) { // some of characters is non-whitespace -#ifdef _MSC_VER // Find the index of first non-whitespace - unsigned long offset; - _BitScanForward(&offset, r); - return p + offset; -#else - return p + __builtin_ffs(r) - 1; -#endif - } + const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); + if (r != 16) // some of characters is non-whitespace + return p + r; } return SkipWhitespace(p, end); @@ -425,7 +413,92 @@ inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { return SkipWhitespace(p, end); } -#endif // RAPIDJSON_SSE2 +#elif defined(RAPIDJSON_NEON) + +//! Skip whitespace with ARM Neon instructions, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char* p) { + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // 16-byte align to the next boundary + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + const uint8x16_t w0 = vmovq_n_u8(' '); + const uint8x16_t w1 = vmovq_n_u8('\n'); + const uint8x16_t w2 = vmovq_n_u8('\r'); + const uint8x16_t w3 = vmovq_n_u8('\t'); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, w0); + x = vorrq_u8(x, vceqq_u8(s, w1)); + x = vorrq_u8(x, vceqq_u8(s, w2)); + x = vorrq_u8(x, vceqq_u8(s, w3)); + + x = vmvnq_u8(x); // Negate + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + if (low == 0) { + if (high != 0) { + int lz =__builtin_clzll(high);; + return p + 8 + (lz >> 3); + } + } else { + int lz = __builtin_clzll(low);; + return p + (lz >> 3); + } + } +} + +inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { + // Fast return for single non-whitespace + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + else + return p; + + const uint8x16_t w0 = vmovq_n_u8(' '); + const uint8x16_t w1 = vmovq_n_u8('\n'); + const uint8x16_t w2 = vmovq_n_u8('\r'); + const uint8x16_t w3 = vmovq_n_u8('\t'); + + for (; p <= end - 16; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, w0); + x = vorrq_u8(x, vceqq_u8(s, w1)); + x = vorrq_u8(x, vceqq_u8(s, w2)); + x = vorrq_u8(x, vceqq_u8(s, w3)); + + x = vmvnq_u8(x); // Negate + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + if (low == 0) { + if (high != 0) { + int lz = __builtin_clzll(high); + return p + 8 + (lz >> 3); + } + } else { + int lz = __builtin_clzll(low); + return p + (lz >> 3); + } + } + + return SkipWhitespace(p, end); +} + +#endif // RAPIDJSON_NEON #ifdef RAPIDJSON_SIMD //! Template function specialization for InsituStringStream @@ -471,7 +544,8 @@ public: /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) */ - GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {} + GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : + stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {} //! Parse JSON text. /*! \tparam parseFlags Combination of \ref ParseFlag. @@ -527,6 +601,83 @@ public: return Parse(is, handler); } + //! Initialize JSON text token-by-token parsing + /*! + */ + void IterativeParseInit() { + parseResult_.Clear(); + state_ = IterativeParsingStartState; + } + + //! Parse one token from JSON text + /*! \tparam InputStream Type of input stream, implementing Stream concept + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + bool IterativeParseNext(InputStream& is, Handler& handler) { + while (RAPIDJSON_LIKELY(is.Peek() != '\0')) { + SkipWhitespaceAndComments(is); + + Token t = Tokenize(is.Peek()); + IterativeParsingState n = Predict(state_, t); + IterativeParsingState d = Transit(state_, t, n, is, handler); + + // If we've finished or hit an error... + if (RAPIDJSON_UNLIKELY(IsIterativeParsingCompleteState(d))) { + // Report errors. + if (d == IterativeParsingErrorState) { + HandleError(state_, is); + return false; + } + + // Transition to the finish state. + RAPIDJSON_ASSERT(d == IterativeParsingFinishState); + state_ = d; + + // If StopWhenDone is not set... + if (!(parseFlags & kParseStopWhenDoneFlag)) { + // ... and extra non-whitespace data is found... + SkipWhitespaceAndComments(is); + if (is.Peek() != '\0') { + // ... this is considered an error. + HandleError(state_, is); + return false; + } + } + + // Success! We are done! + return true; + } + + // Transition to the new state. + state_ = d; + + // If we parsed anything other than a delimiter, we invoked the handler, so we can return true now. + if (!IsIterativeParsingDelimiterState(n)) + return true; + } + + // We reached the end of file. + stack_.Clear(); + + if (state_ != IterativeParsingFinishState) { + HandleError(state_, is); + return false; + } + + return true; + } + + //! Check if token-by-token parsing JSON text is complete + /*! \return Whether the JSON has been fully decoded. + */ + RAPIDJSON_FORCEINLINE bool IterativeParseComplete() { + return IsIterativeParsingCompleteState(state_); + } + //! Whether a parse error has occured in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } @@ -575,7 +726,7 @@ private: } } else if (RAPIDJSON_LIKELY(Consume(is, '/'))) - while (is.Peek() != '\0' && is.Take() != '\n'); + while (is.Peek() != '\0' && is.Take() != '\n') {} else RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); @@ -892,7 +1043,7 @@ private: if (c == '\0') RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell()); else - RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell()); + RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); } else { size_t offset = is.Tell(); @@ -927,7 +1078,7 @@ private: // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); @@ -936,7 +1087,7 @@ private: const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped @@ -948,11 +1099,13 @@ private: #else length = static_cast(__builtin_ffs(r) - 1); #endif - char* q = reinterpret_cast(os.Push(length)); - for (size_t i = 0; i < length; i++) - q[i] = p[i]; + if (length != 0) { + char* q = reinterpret_cast(os.Push(length)); + for (size_t i = 0; i < length; i++) + q[i] = p[i]; - p += length; + p += length; + } break; } _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s); @@ -988,7 +1141,7 @@ private: // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); @@ -997,7 +1150,7 @@ private: const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped @@ -1036,7 +1189,7 @@ private: // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); @@ -1045,7 +1198,7 @@ private: const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped @@ -1064,7 +1217,180 @@ private: is.src_ = is.dst_ = p; } -#endif +#elif defined(RAPIDJSON_NEON) + // StringStream -> StackStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { + const char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + return; + } + else + os.Put(*p++); + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + SizeType length = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + unsigned lz = (unsigned)__builtin_clzll(high);; + length = 8 + (lz >> 3); + escaped = true; + } + } else { + unsigned lz = (unsigned)__builtin_clzll(low);; + length = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + if (length != 0) { + char* q = reinterpret_cast(os.Push(length)); + for (size_t i = 0; i < length; i++) + q[i] = p[i]; + + p += length; + } + break; + } + vst1q_u8(reinterpret_cast(os.Push(16)), s); + } + + is.src_ = p; + } + + // InsituStringStream -> InsituStringStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { + RAPIDJSON_ASSERT(&is == &os); + (void)os; + + if (is.src_ == is.dst_) { + SkipUnescapedString(is); + return; + } + + char* p = is.src_; + char *q = is.dst_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + is.dst_ = q; + return; + } + else + *q++ = *p++; + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16, q += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + SizeType length = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + unsigned lz = (unsigned)__builtin_clzll(high); + length = 8 + (lz >> 3); + escaped = true; + } + } else { + unsigned lz = (unsigned)__builtin_clzll(low); + length = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + for (const char* pend = p + length; p != pend; ) { + *q++ = *p++; + } + break; + } + vst1q_u8(reinterpret_cast(q), s); + } + + is.src_ = p; + is.dst_ = q; + } + + // When read/write pointers are the same for insitu stream, just skip unescaped characters + static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { + RAPIDJSON_ASSERT(is.src_ == is.dst_); + char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + for (; p != nextAligned; p++) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = is.dst_ = p; + return; + } + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + if (low == 0) { + if (high != 0) { + int lz = __builtin_clzll(high); + p += 8 + (lz >> 3); + break; + } + } else { + int lz = __builtin_clzll(low); + p += lz >> 3; + break; + } + } + + is.src_ = is.dst_ = p; + } +#endif // RAPIDJSON_NEON template class NumberStream; @@ -1075,7 +1401,6 @@ private: typedef typename InputStream::Ch Ch; NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; } - ~NumberStream() {} RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } @@ -1097,7 +1422,6 @@ private: typedef NumberStream Base; public: NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {} - ~NumberStream() {} RAPIDJSON_FORCEINLINE Ch TakePush() { stackStream.Put(static_cast(Base::is.Peek())); @@ -1124,7 +1448,6 @@ private: typedef NumberStream Base; public: NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {} - ~NumberStream() {} RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); } }; @@ -1185,18 +1508,27 @@ private: } // Parse NaN or Infinity here else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) { - useNanOrInf = true; - if (RAPIDJSON_LIKELY(Consume(s, 'N') && Consume(s, 'a') && Consume(s, 'N'))) { - d = std::numeric_limits::quiet_NaN(); + if (Consume(s, 'N')) { + if (Consume(s, 'a') && Consume(s, 'N')) { + d = std::numeric_limits::quiet_NaN(); + useNanOrInf = true; + } } - else if (RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && Consume(s, 'f'))) { - d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); - if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') - && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + else if (RAPIDJSON_LIKELY(Consume(s, 'I'))) { + if (Consume(s, 'n') && Consume(s, 'f')) { + d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); + useNanOrInf = true; + + if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') + && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) { + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } + } } - else + + if (RAPIDJSON_UNLIKELY(!useNanOrInf)) { RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); @@ -1408,30 +1740,32 @@ private: // States enum IterativeParsingState { - IterativeParsingStartState = 0, - IterativeParsingFinishState, - IterativeParsingErrorState, + IterativeParsingFinishState = 0, // sink states at top + IterativeParsingErrorState, // sink states at top + IterativeParsingStartState, // Object states IterativeParsingObjectInitialState, IterativeParsingMemberKeyState, - IterativeParsingKeyValueDelimiterState, IterativeParsingMemberValueState, - IterativeParsingMemberDelimiterState, IterativeParsingObjectFinishState, // Array states IterativeParsingArrayInitialState, IterativeParsingElementState, - IterativeParsingElementDelimiterState, IterativeParsingArrayFinishState, // Single value state - IterativeParsingValueState + IterativeParsingValueState, + + // Delimiter states (at bottom) + IterativeParsingElementDelimiterState, + IterativeParsingMemberDelimiterState, + IterativeParsingKeyValueDelimiterState, + + cIterativeParsingStateCount }; - enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 }; - // Tokens enum Token { LeftBracketToken = 0, @@ -1482,6 +1816,18 @@ private: RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) { // current state x one lookahead token -> new state static const char G[cIterativeParsingStateCount][kTokenCount] = { + // Finish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Error(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, // Start { IterativeParsingArrayInitialState, // Left bracket @@ -1496,18 +1842,6 @@ private: IterativeParsingValueState, // Null IterativeParsingValueState // Number }, - // Finish(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // Error(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, // ObjectInitial { IterativeParsingErrorState, // Left bracket @@ -1536,20 +1870,6 @@ private: IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, - // KeyValueDelimiter - { - IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) - IterativeParsingErrorState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberValueState, // String - IterativeParsingMemberValueState, // False - IterativeParsingMemberValueState, // True - IterativeParsingMemberValueState, // Null - IterativeParsingMemberValueState // Number - }, // MemberValue { IterativeParsingErrorState, // Left bracket @@ -1564,20 +1884,6 @@ private: IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, - // MemberDelimiter - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingObjectFinishState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberKeyState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, // ObjectFinish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, @@ -1612,6 +1918,18 @@ private: IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, + // ArrayFinish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Single Value (sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, // ElementDelimiter { IterativeParsingArrayInitialState, // Left bracket(push Element state) @@ -1626,18 +1944,34 @@ private: IterativeParsingElementState, // Null IterativeParsingElementState // Number }, - // ArrayFinish(sink state) + // MemberDelimiter { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberKeyState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number }, - // Single Value (sink state) + // KeyValueDelimiter { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - } + IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberValueState, // String + IterativeParsingMemberValueState, // False + IterativeParsingMemberValueState, // True + IterativeParsingMemberValueState, // Null + IterativeParsingMemberValueState // Number + }, }; // End of G return static_cast(G[state][token]); @@ -1818,44 +2152,53 @@ private: } } + RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) { + return s >= IterativeParsingElementDelimiterState; + } + + RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) { + return s <= IterativeParsingErrorState; + } + template ParseResult IterativeParse(InputStream& is, Handler& handler) { parseResult_.Clear(); ClearStackOnExit scope(*this); IterativeParsingState state = IterativeParsingStartState; - + SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); while (is.Peek() != '\0') { Token t = Tokenize(is.Peek()); IterativeParsingState n = Predict(state, t); IterativeParsingState d = Transit(state, t, n, is, handler); - + if (d == IterativeParsingErrorState) { HandleError(state, is); break; } - + state = d; - + // Do not further consume streams if a root JSON has been parsed. if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) break; - + SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } - + // Handle the end of file. if (state != IterativeParsingFinishState) HandleError(state, is); - + return parseResult_; } static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. ParseResult parseResult_; + IterativeParsingState state_; }; // class GenericReader //! Reader with UTF8 encoding and default allocator. diff --git a/src/3rdparty/rapidjson/schema.h b/src/3rdparty/rapidjson/schema.h index b182aa27..2713fb26 100644 --- a/src/3rdparty/rapidjson/schema.h +++ b/src/3rdparty/rapidjson/schema.h @@ -349,11 +349,13 @@ public: Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) : allocator_(allocator), + typeless_(schemaDocument->GetTypeless()), enum_(), enumCount_(), not_(), type_((1 << kTotalSchemaType) - 1), // typeless validatorCount_(), + notValidatorIndex_(), properties_(), additionalPropertiesSchema_(), patternProperties_(), @@ -453,7 +455,7 @@ public: for (SizeType i = 0; i < propertyCount_; i++) { new (&properties_[i]) Property(); properties_[i].name = allProperties[i]; - properties_[i].schema = GetTypeless(); + properties_[i].schema = typeless_; } } } @@ -575,9 +577,7 @@ public: } ~Schema() { - if (allocator_) { - allocator_->Free(enum_); - } + AllocatorType::Free(enum_); if (properties_) { for (SizeType i = 0; i < propertyCount_; i++) properties_[i].~Property(); @@ -592,7 +592,7 @@ public: #if RAPIDJSON_SCHEMA_HAS_REGEX if (pattern_) { pattern_->~RegexType(); - allocator_->Free(pattern_); + AllocatorType::Free(pattern_); } #endif } @@ -610,12 +610,12 @@ public: else if (additionalItemsSchema_) context.valueSchema = additionalItemsSchema_; else if (additionalItems_) - context.valueSchema = GetTypeless(); + context.valueSchema = typeless_; else RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString()); } else - context.valueSchema = GetTypeless(); + context.valueSchema = typeless_; context.arrayElementIndex++; } @@ -784,15 +784,17 @@ public: if (patternProperties_) { context.patternPropertiesSchemaCount = 0; for (SizeType i = 0; i < patternPropertyCount_; i++) - if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) + if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema; + context.valueSchema = typeless_; + } } SizeType index; if (FindPropertyIndex(ValueType(str, len).Move(), &index)) { if (context.patternPropertiesSchemaCount > 0) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; - context.valueSchema = GetTypeless(); + context.valueSchema = typeless_; context.valuePatternValidatorType = Context::kPatternValidatorWithProperty; } else @@ -807,7 +809,7 @@ public: if (additionalPropertiesSchema_) { if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_; - context.valueSchema = GetTypeless(); + context.valueSchema = typeless_; context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty; } else @@ -815,7 +817,7 @@ public: return true; } else if (additionalProperties_) { - context.valueSchema = GetTypeless(); + context.valueSchema = typeless_; return true; } @@ -881,7 +883,7 @@ public: #define RAPIDJSON_STRING_(name, ...) \ static const ValueType& Get##name##String() {\ static const Ch s[] = { __VA_ARGS__, '\0' };\ - static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\ + static const ValueType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1));\ return v;\ } @@ -934,7 +936,7 @@ private: }; #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX - typedef internal::GenericRegex RegexType; + typedef internal::GenericRegex RegexType; #elif RAPIDJSON_SCHEMA_USE_STDREGEX typedef std::basic_regex RegexType; #else @@ -949,11 +951,6 @@ private: SizeType count; }; - static const SchemaType* GetTypeless() { - static SchemaType typeless(0, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0); - return &typeless; - } - template void AddUniqueElement(V1& a, const V2& v) { for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) @@ -999,7 +996,7 @@ private: template RegexType* CreatePattern(const ValueType& value) { if (value.IsString()) { - RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString()); + RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_); if (!r->IsValid()) { r->~RegexType(); AllocatorType::Free(r); @@ -1011,7 +1008,8 @@ private: } static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) { - return pattern->Search(str); + GenericRegexSearch rs(*pattern); + return rs.Search(str); } #elif RAPIDJSON_SCHEMA_USE_STDREGEX template @@ -1117,8 +1115,8 @@ private: if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); } - else if (maximum_.IsUint64()) - /* do nothing */; // i <= max(int64_t) < maximum_.GetUint64() + else if (maximum_.IsUint64()) { } + /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64() else if (!CheckDoubleMaximum(context, static_cast(i))) return false; } @@ -1218,6 +1216,7 @@ private: }; AllocatorType* allocator_; + const SchemaType* typeless_; uint64_t* enum_; SizeType enumCount_; SchemaArray allOf_; @@ -1267,7 +1266,7 @@ struct TokenHelper { char buffer[21]; size_t length = static_cast((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer); for (size_t i = 0; i < length; i++) - *documentStack.template Push() = buffer[i]; + *documentStack.template Push() = static_cast(buffer[i]); } }; @@ -1343,11 +1342,15 @@ public: allocator_(allocator), ownAllocator_(), root_(), + typeless_(), schemaMap_(allocator, kInitialSchemaMapSize), schemaRef_(allocator, kInitialSchemaRefSize) { if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + + typeless_ = static_cast(allocator_->Malloc(sizeof(SchemaType))); + new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0); // Generate root schema, it will call CreateSchema() to create sub-schemas, // And call AddRefSchema() if there are $ref. @@ -1365,6 +1368,9 @@ public: new (schemaMap_.template Push()) SchemaEntry(refEntry->source, const_cast(s), false, allocator_); } } + else if (refEntry->schema) + *refEntry->schema = typeless_; + refEntry->~SchemaRefEntry(); } @@ -1380,12 +1386,14 @@ public: allocator_(rhs.allocator_), ownAllocator_(rhs.ownAllocator_), root_(rhs.root_), + typeless_(rhs.typeless_), schemaMap_(std::move(rhs.schemaMap_)), schemaRef_(std::move(rhs.schemaRef_)) { rhs.remoteProvider_ = 0; rhs.allocator_ = 0; rhs.ownAllocator_ = 0; + rhs.typeless_ = 0; } #endif @@ -1394,6 +1402,11 @@ public: while (!schemaMap_.Empty()) schemaMap_.template Pop(1)->~SchemaEntry(); + if (typeless_) { + typeless_->~SchemaType(); + Allocator::Free(typeless_); + } + RAPIDJSON_DELETE(ownAllocator_); } @@ -1428,7 +1441,7 @@ private: void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { if (schema) - *schema = SchemaType::GetTypeless(); + *schema = typeless_; if (v.GetType() == kObjectType) { const SchemaType* s = GetSchema(pointer); @@ -1473,7 +1486,7 @@ private: if (i > 0) { // Remote reference, resolve immediately if (remoteProvider_) { - if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) { + if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) { PointerType pointer(&s[i], len - i, allocator_); if (pointer.IsValid()) { if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) { @@ -1515,6 +1528,8 @@ private: return PointerType(); } + const SchemaType* GetTypeless() const { return typeless_; } + static const size_t kInitialSchemaMapSize = 64; static const size_t kInitialSchemaRefSize = 64; @@ -1522,6 +1537,7 @@ private: Allocator *allocator_; Allocator *ownAllocator_; const SchemaType* root_; //!< Root schema. + SchemaType* typeless_; internal::Stack schemaMap_; // Stores created Pointer -> Schemas internal::Stack schemaRef_; // Stores Pointer from $ref and schema which holds the $ref }; @@ -1575,11 +1591,11 @@ public: : schemaDocument_(&schemaDocument), root_(schemaDocument.GetRoot()), - outputHandler_(GetNullHandler()), stateAllocator_(allocator), ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), + outputHandler_(0), valid_(true) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(0) @@ -1603,11 +1619,11 @@ public: : schemaDocument_(&schemaDocument), root_(schemaDocument.GetRoot()), - outputHandler_(outputHandler), stateAllocator_(allocator), ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), + outputHandler_(&outputHandler), valid_(true) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(0) @@ -1679,7 +1695,7 @@ RAPIDJSON_MULTILINEMACRO_END } #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ - return valid_ = EndValue() && outputHandler_.method arg2 + return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2) #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ @@ -1701,7 +1717,7 @@ RAPIDJSON_MULTILINEMACRO_END bool StartObject() { RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); - return valid_ = outputHandler_.StartObject(); + return valid_ = !outputHandler_ || outputHandler_->StartObject(); } bool Key(const Ch* str, SizeType len, bool copy) { @@ -1709,7 +1725,7 @@ RAPIDJSON_MULTILINEMACRO_END AppendToken(str, len); if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); - return valid_ = outputHandler_.Key(str, len, copy); + return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy); } bool EndObject(SizeType memberCount) { @@ -1722,7 +1738,7 @@ RAPIDJSON_MULTILINEMACRO_END bool StartArray() { RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); - return valid_ = outputHandler_.StartArray(); + return valid_ = !outputHandler_ || outputHandler_->StartArray(); } bool EndArray(SizeType elementCount) { @@ -1771,7 +1787,7 @@ RAPIDJSON_MULTILINEMACRO_END } virtual void FreeState(void* p) { - return StateAllocator::Free(p); + StateAllocator::Free(p); } private: @@ -1791,11 +1807,11 @@ private: : schemaDocument_(&schemaDocument), root_(root), - outputHandler_(GetNullHandler()), stateAllocator_(allocator), ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), + outputHandler_(0), valid_(true) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(depth) @@ -1805,7 +1821,7 @@ private: StateAllocator& GetStateAllocator() { if (!stateAllocator_) - stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator()); + stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)(); return *stateAllocator_; } @@ -1823,8 +1839,8 @@ private: const SchemaType** sa = CurrentContext().patternPropertiesSchemas; typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType; bool valueUniqueness = CurrentContext().valueUniqueness; - if (CurrentContext().valueSchema) - PushSchema(*CurrentContext().valueSchema); + RAPIDJSON_ASSERT(CurrentContext().valueSchema); + PushSchema(*CurrentContext().valueSchema); if (count > 0) { CurrentContext().objectPatternValidatorType = patternValidatorType; @@ -1909,20 +1925,15 @@ private: Context& CurrentContext() { return *schemaStack_.template Top(); } const Context& CurrentContext() const { return *schemaStack_.template Top(); } - static OutputHandler& GetNullHandler() { - static OutputHandler nullHandler; - return nullHandler; - } - static const size_t kDefaultSchemaStackCapacity = 1024; static const size_t kDefaultDocumentStackCapacity = 256; const SchemaDocumentType* schemaDocument_; const SchemaType& root_; - OutputHandler& outputHandler_; StateAllocator* stateAllocator_; StateAllocator* ownStateAllocator_; internal::Stack schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) internal::Stack documentStack_; //!< stack to store the current path of validating document (Ch) + OutputHandler* outputHandler_; bool valid_; #if RAPIDJSON_SCHEMA_VERBOSE unsigned depth_; diff --git a/src/3rdparty/rapidjson/stream.h b/src/3rdparty/rapidjson/stream.h index fef82c25..7f2643e4 100644 --- a/src/3rdparty/rapidjson/stream.h +++ b/src/3rdparty/rapidjson/stream.h @@ -1,5 +1,5 @@ // Tencent is pleased to support the open source community by making RapidJSON available. -// +// // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except @@ -7,9 +7,9 @@ // // http://opensource.org/licenses/MIT // -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #include "rapidjson.h" @@ -100,6 +100,50 @@ inline void PutN(Stream& stream, Ch c, size_t n) { PutUnsafe(stream, c); } +/////////////////////////////////////////////////////////////////////////////// +// GenericStreamWrapper + +//! A Stream Wrapper +/*! \tThis string stream is a wrapper for any stream by just forwarding any + \treceived message to the origin stream. + \note implements Stream concept +*/ + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4702) // unreachable code +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +template > +class GenericStreamWrapper { +public: + typedef typename Encoding::Ch Ch; + GenericStreamWrapper(InputStream& is): is_(is) {} + + Ch Peek() const { return is_.Peek(); } + Ch Take() { return is_.Take(); } + size_t Tell() { return is_.Tell(); } + Ch* PutBegin() { return is_.PutBegin(); } + void Put(Ch ch) { is_.Put(ch); } + void Flush() { is_.Flush(); } + size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); } + + // wrapper for MemoryStream + const Ch* Peek4() const { return is_.Peek4(); } + + // wrapper for AutoUTFInputStream + UTFType GetType() const { return is_.GetType(); } + bool HasBOM() const { return is_.HasBOM(); } + +protected: + InputStream& is_; +}; + +#if defined(_MSC_VER) && _MSC_VER <= 1800 +RAPIDJSON_DIAG_POP +#endif + /////////////////////////////////////////////////////////////////////////////// // StringStream diff --git a/src/3rdparty/rapidjson/stringbuffer.h b/src/3rdparty/rapidjson/stringbuffer.h index 78f34d20..4e38b82c 100644 --- a/src/3rdparty/rapidjson/stringbuffer.h +++ b/src/3rdparty/rapidjson/stringbuffer.h @@ -78,8 +78,12 @@ public: return stack_.template Bottom(); } + //! Get the size of string in bytes in the string buffer. size_t GetSize() const { return stack_.GetSize(); } + //! Get the length of string in Ch in the string buffer. + size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); } + static const size_t kDefaultCapacity = 256; mutable internal::Stack stack_; diff --git a/src/3rdparty/rapidjson/writer.h b/src/3rdparty/rapidjson/writer.h index 94f22dd5..e610ebb6 100644 --- a/src/3rdparty/rapidjson/writer.h +++ b/src/3rdparty/rapidjson/writer.h @@ -16,6 +16,7 @@ #define RAPIDJSON_WRITER_H_ #include "stream.h" +#include "internal/meta.h" #include "internal/stack.h" #include "internal/strfunc.h" #include "internal/dtoa.h" @@ -31,6 +32,8 @@ #include #elif defined(RAPIDJSON_SSE2) #include +#elif defined(RAPIDJSON_NEON) +#include #endif #ifdef _MSC_VER @@ -42,6 +45,7 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(c++98-compat) #endif RAPIDJSON_NAMESPACE_BEGIN @@ -103,6 +107,13 @@ public: Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + Writer(Writer&& rhs) : + os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) { + rhs.os_ = 0; + } +#endif + //! Reset the writer with a new stream. /*! This function reset the writer with a new stream and default settings, @@ -184,12 +195,14 @@ public: bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); } bool RawNumber(const Ch* str, SizeType length, bool copy = false) { + RAPIDJSON_ASSERT(str != 0); (void)copy; Prefix(kNumberType); return EndValue(WriteString(str, length)); } bool String(const Ch* str, SizeType length, bool copy = false) { + RAPIDJSON_ASSERT(str != 0); (void)copy; Prefix(kStringType); return EndValue(WriteString(str, length)); @@ -209,10 +222,18 @@ public: bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } +#if RAPIDJSON_HAS_STDSTRING + bool Key(const std::basic_string& str) + { + return Key(str.data(), SizeType(str.size())); + } +#endif + bool EndObject(SizeType memberCount = 0) { (void)memberCount; - RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); - RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object + RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); // currently inside an Array, not Object + RAPIDJSON_ASSERT(0 == level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value level_stack_.template Pop(1); return EndValue(WriteEndObject()); } @@ -236,9 +257,9 @@ public: //@{ //! Simpler but slower overload. - bool String(const Ch* str) { return String(str, internal::StrLen(str)); } - bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } - + bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); } + bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); } + //@} //! Write a raw JSON value. @@ -249,7 +270,19 @@ public: \param length Length of the json. \param type Type of the root of json. */ - bool RawValue(const Ch* json, size_t length, Type type) { Prefix(type); return EndValue(WriteRawValue(json, length)); } + bool RawValue(const Ch* json, size_t length, Type type) { + RAPIDJSON_ASSERT(json != 0); + Prefix(type); + return EndValue(WriteRawValue(json, length)); + } + + //! Flush the output stream. + /*! + Allows the user to flush the output stream immediately. + */ + void Flush() { + os_->Flush(); + } protected: //! Information for each nested level @@ -283,7 +316,7 @@ protected: const char* end = internal::i32toa(i, buffer); PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); + PutUnsafe(*os_, static_cast(*p)); return true; } @@ -292,7 +325,7 @@ protected: const char* end = internal::u32toa(u, buffer); PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); + PutUnsafe(*os_, static_cast(*p)); return true; } @@ -301,7 +334,7 @@ protected: const char* end = internal::i64toa(i64, buffer); PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); + PutUnsafe(*os_, static_cast(*p)); return true; } @@ -310,7 +343,7 @@ protected: char* end = internal::u64toa(u64, buffer); PutReserve(*os_, static_cast(end - buffer)); for (char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); + PutUnsafe(*os_, static_cast(*p)); return true; } @@ -338,12 +371,12 @@ protected: char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); PutReserve(*os_, static_cast(end - buffer)); for (char* p = buffer; p != end; ++p) - PutUnsafe(*os_, static_cast(*p)); + PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteString(const Ch* str, SizeType length) { - static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static const char escape[256] = { #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //0 1 2 3 4 5 6 7 8 9 A B C D E F @@ -399,7 +432,7 @@ protected: else if ((sizeof(Ch) == 1 || static_cast(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast(c)])) { is.Take(); PutUnsafe(*os_, '\\'); - PutUnsafe(*os_, static_cast(escape[static_cast(c)])); + PutUnsafe(*os_, static_cast(escape[static_cast(c)])); if (escape[static_cast(c)] == 'u') { PutUnsafe(*os_, '0'); PutUnsafe(*os_, '0'); @@ -457,7 +490,7 @@ protected: // Flush the value if it is the top level one. bool EndValue(bool ret) { if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text - os_->Flush(); + Flush(); return ret; } @@ -561,7 +594,7 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; - static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); @@ -570,7 +603,7 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); - const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19 + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped @@ -595,7 +628,75 @@ inline bool Writer::ScanWriteUnescapedString(StringStream& is, siz is.src_ = p; return RAPIDJSON_LIKELY(is.Tell() < length); } -#endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) +#elif defined(RAPIDJSON_NEON) +template<> +inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { + if (length < 16) + return RAPIDJSON_LIKELY(is.Tell() < length); + + if (!RAPIDJSON_LIKELY(is.Tell() < length)) + return false; + + const char* p = is.src_; + const char* end = is.head_ + length; + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); + if (nextAligned > end) + return true; + + while (p != nextAligned) + if (*p < 0x20 || *p == '\"' || *p == '\\') { + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); + } + else + os_->PutUnsafe(*p++); + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (; p != endAligned; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + SizeType len = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + unsigned lz = (unsigned)__builtin_clzll(high); + len = 8 + (lz >> 3); + escaped = true; + } + } else { + unsigned lz = (unsigned)__builtin_clzll(low); + len = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + char* q = reinterpret_cast(os_->PushUnsafe(len)); + for (size_t i = 0; i < len; i++) + q[i] = p[i]; + + p += len; + break; + } + vst1q_u8(reinterpret_cast(os_->PushUnsafe(16)), s); + } + + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); +} +#endif // RAPIDJSON_NEON RAPIDJSON_NAMESPACE_END