Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
cpuid.cc
Go to the documentation of this file.
1// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/globals.h"
6#if !defined(DART_HOST_OS_MACOS)
7#include "vm/cpuid.h"
8#include "vm/flags.h"
9#include "vm/os.h"
10
11#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
12// GetCpuId() on Windows, __get_cpuid() on Linux
13#if defined(DART_HOST_OS_WINDOWS)
14#include <intrin.h> // NOLINT
15#else
16#include <cpuid.h> // NOLINT
17#endif
18#endif
19
20namespace dart {
21
22DEFINE_FLAG(bool, trace_cpuid, false, "Trace CPU ID discovery")
23
24bool CpuId::sse2_ = false;
25bool CpuId::sse41_ = false;
26bool CpuId::popcnt_ = false;
27bool CpuId::abm_ = false;
28
29const char* CpuId::id_string_ = nullptr;
30const char* CpuId::brand_string_ = nullptr;
31
32#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
33
34static void GetCpuId(int32_t level, uint32_t info[4]) {
35#if defined(DART_HOST_OS_WINDOWS)
36 // The documentation for __cpuid is at:
37 // http://msdn.microsoft.com/en-us/library/hskdteyh(v=vs.90).aspx
38 __cpuid(reinterpret_cast<int*>(info), level);
39#else
40 __get_cpuid(level, &info[0], &info[1], &info[2], &info[3]);
41#endif
42}
43
44void CpuId::Init() {
45 const int info_length = 4;
46 uint32_t info[info_length] = {static_cast<uint32_t>(-1)};
47
48 GetCpuId(0, info);
49 if (FLAG_trace_cpuid) {
50 for (intptr_t i = 0; i < info_length; i++) {
51 OS::PrintErr("cpuid(0) info[%" Pd "]: %0x\n", i, info[i]);
52 }
53 }
54
55 char* id_string = reinterpret_cast<char*>(malloc(3 * sizeof(int32_t)));
56
57 // Yes, these are supposed to be out of order.
58 *reinterpret_cast<uint32_t*>(id_string) = info[1];
59 *reinterpret_cast<uint32_t*>(id_string + 4) = info[3];
60 *reinterpret_cast<uint32_t*>(id_string + 8) = info[2];
61 CpuId::id_string_ = id_string;
62 if (FLAG_trace_cpuid) {
63 OS::PrintErr("id_string: %s\n", id_string);
64 }
65
66 GetCpuId(1, info);
67 if (FLAG_trace_cpuid) {
68 for (intptr_t i = 0; i < info_length; i++) {
69 OS::PrintErr("cpuid(1) info[%" Pd "]: %0x\n", i, info[i]);
70 }
71 }
72 CpuId::sse41_ = (info[2] & (1 << 19)) != 0;
73 CpuId::sse2_ = (info[3] & (1 << 26)) != 0;
74 CpuId::popcnt_ = (info[2] & (1 << 23)) != 0;
75 if (FLAG_trace_cpuid) {
76 OS::PrintErr("sse41? %s sse2? %s popcnt? %s\n",
77 CpuId::sse41_ ? "yes" : "no", CpuId::sse2_ ? "yes" : "no",
78 CpuId::popcnt_ ? "yes" : "no");
79 }
80
81 GetCpuId(0x80000001, info);
82 if (FLAG_trace_cpuid) {
83 for (intptr_t i = 0; i < info_length; i++) {
84 OS::PrintErr("cpuid(0x80000001) info[%" Pd "]: %0x\n", i, info[i]);
85 }
86 }
87 CpuId::abm_ = (info[2] & (1 << 5)) != 0;
88
89 // Brand string returned by CPUID is expected to be nullptr-terminated,
90 // however we have seen cases in the wild which violate this assumption.
91 // To avoid going out of bounds when trying to print this string
92 // we add null-terminator ourselves, just in case.
93 //
94 // See https://github.com/flutter/flutter/issues/114346
95 char* brand_string = reinterpret_cast<char*>(calloc(3 * sizeof(info) + 1, 1));
96 for (uint32_t i = 0; i < 2; i++) {
97 GetCpuId(0x80000002U + i, info);
98 if (FLAG_trace_cpuid) {
99 for (intptr_t j = 0; j < info_length; j++) {
100 OS::PrintErr("cpuid(0x80000002U + %u) info[%" Pd "]: %0x\n", i, j,
101 info[j]);
102 }
103 }
104 memmove(&brand_string[i * sizeof(info)], &info, sizeof(info));
105 }
106 CpuId::brand_string_ = brand_string;
107 if (FLAG_trace_cpuid) {
108 OS::PrintErr("brand_string: %s\n", brand_string_);
109 }
110}
111
112void CpuId::Cleanup() {
113 ASSERT(id_string_ != nullptr);
114 free(const_cast<char*>(id_string_));
115 id_string_ = nullptr;
116
117 ASSERT(brand_string_ != nullptr);
118 free(const_cast<char*>(brand_string_));
119 brand_string_ = nullptr;
120}
121
122const char* CpuId::id_string() {
123 return Utils::StrDup(id_string_);
124}
125
126const char* CpuId::brand_string() {
127 return Utils::StrDup(brand_string_);
128}
129
130const char* CpuId::field(CpuInfoIndices idx) {
131 switch (idx) {
133 return id_string();
134 case kCpuInfoModel:
135 return brand_string();
136 case kCpuInfoHardware:
137 return brand_string();
138 case kCpuInfoFeatures: {
139 char buffer[100];
140 char* p = buffer;
141 const char* q = p + 100;
142 *p = '\0';
143 if (sse2()) {
144 p += snprintf(p, q - p, "sse2 ");
145 }
146 if (sse41()) {
147 p += snprintf(p, q - p, "sse4.1 ");
148 }
149 if (popcnt()) {
150 p += snprintf(p, q - p, "popcnt ");
151 }
152 if (abm()) {
153 p += snprintf(p, q - p, "abm ");
154 }
155 // Remove last space before returning string.
156 if (p != buffer) *(p - 1) = '\0';
157 return Utils::StrDup(buffer);
158 }
159 default: {
160 UNREACHABLE();
161 return nullptr;
162 }
163 }
164}
165
166#endif // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
167} // namespace dart
168
169#endif // !defined(DART_HOST_OS_MACOS)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
#define UNREACHABLE()
Definition assert.h:248
static void Cleanup()
Definition cpuid.h:25
static void Init()
Definition cpuid.h:24
static const char * field(CpuInfoIndices idx)
Definition cpuid.h:26
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static char * StrDup(const char *s)
#define ASSERT(E)
static const uint8_t buffer[]
#define DEFINE_FLAG(type, name, default_value, comment)
Definition flags.h:16
void * malloc(size_t size)
Definition allocation.cc:19
CpuInfoIndices
Definition cpuinfo.h:15
@ kCpuInfoFeatures
Definition cpuinfo.h:19
@ kCpuInfoProcessor
Definition cpuinfo.h:16
@ kCpuInfoHardware
Definition cpuinfo.h:18
@ kCpuInfoModel
Definition cpuinfo.h:17
void * calloc(size_t n, size_t size)
Definition allocation.cc:11
#define Pd
Definition globals.h:408