1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <array>
18
19 #include "common_runtime_test.h"
20 #include "instruction_set_features.h"
21
22 #include <gtest/gtest.h>
23
24 #ifdef ART_TARGET_ANDROID
25 #include <android-base/properties.h>
26 #endif
27
28 #include <android-base/logging.h>
29 #include <android-base/stringprintf.h>
30
31 namespace art {
32
33 #ifdef ART_TARGET_ANDROID
34
35 using android::base::StringPrintf;
36
37 #if defined(__aarch64__)
TEST(InstructionSetFeaturesTest,DISABLED_FeaturesFromSystemPropertyVariant)38 TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromSystemPropertyVariant) {
39 LOG(WARNING) << "Test disabled due to no CPP define for A53 erratum 835769";
40 #else
41 TEST(InstructionSetFeaturesTest, FeaturesFromSystemPropertyVariant) {
42 #endif
43 if (kIsTargetBuild) {
44 // atest differs in build-time and run-time features.
45 TEST_DISABLED_FOR_X86();
46 TEST_DISABLED_FOR_X86_64();
47 }
48
49 // Take the default set of instruction features from the build.
50 std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
51 InstructionSetFeatures::FromCppDefines());
52
53 // Read the variant property.
54 std::string key = StringPrintf("dalvik.vm.isa.%s.variant", GetInstructionSetString(kRuntimeISA));
55 std::string dex2oat_isa_variant = android::base::GetProperty(key, "");
56 if (!dex2oat_isa_variant.empty()) {
57 // Use features from property to build InstructionSetFeatures and check against build's
58 // features.
59 std::string error_msg;
60 std::unique_ptr<const InstructionSetFeatures> property_features(
61 InstructionSetFeatures::FromVariant(kRuntimeISA, dex2oat_isa_variant, &error_msg));
62 ASSERT_TRUE(property_features.get() != nullptr) << error_msg;
63
64 EXPECT_TRUE(property_features->HasAtLeast(instruction_set_features.get()))
65 << "System property features: " << *property_features.get()
66 << "\nFeatures from build: " << *instruction_set_features.get();
67 }
68 }
69
70 #if defined(__aarch64__)
71 TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromSystemPropertyString) {
72 LOG(WARNING) << "Test disabled due to no CPP define for A53 erratum 835769";
73 #else
74 TEST(InstructionSetFeaturesTest, FeaturesFromSystemPropertyString) {
75 #endif
76 if (kIsTargetBuild) {
77 // atest differs in build-time and run-time features.
78 TEST_DISABLED_FOR_X86();
79 TEST_DISABLED_FOR_X86_64();
80 }
81
82 // Take the default set of instruction features from the build.
83 std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
84 InstructionSetFeatures::FromCppDefines());
85
86 // Read the variant property.
87 std::string variant_key = StringPrintf("dalvik.vm.isa.%s.variant",
88 GetInstructionSetString(kRuntimeISA));
89 std::string dex2oat_isa_variant = android::base::GetProperty(variant_key, "");
90 if (!dex2oat_isa_variant.empty()) {
91 // Read the features property.
92 std::string features_key = StringPrintf("dalvik.vm.isa.%s.features",
93 GetInstructionSetString(kRuntimeISA));
94 std::string dex2oat_isa_features = android::base::GetProperty(features_key, "");
95 if (!dex2oat_isa_features.empty()) {
96 // Use features from property to build InstructionSetFeatures and check against build's
97 // features.
98 std::string error_msg;
99 std::unique_ptr<const InstructionSetFeatures> base_features(
100 InstructionSetFeatures::FromVariant(kRuntimeISA, dex2oat_isa_variant, &error_msg));
101 ASSERT_TRUE(base_features.get() != nullptr) << error_msg;
102
103 std::unique_ptr<const InstructionSetFeatures> property_features(
104 base_features->AddFeaturesFromString(dex2oat_isa_features, &error_msg));
105 ASSERT_TRUE(property_features.get() != nullptr) << error_msg;
106
107 EXPECT_TRUE(property_features->HasAtLeast(instruction_set_features.get()))
108 << "System property features: " << *property_features.get()
109 << "\nFeatures from build: " << *instruction_set_features.get();
110 }
111 }
112 }
113
114 #if defined(__arm__)
115 TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromCpuInfo) {
116 LOG(WARNING) << "Test disabled due to buggy ARM kernels";
117 #else
118 TEST(InstructionSetFeaturesTest, FeaturesFromCpuInfo) {
119 #endif
120 // Take the default set of instruction features from the build.
121 std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
122 InstructionSetFeatures::FromCppDefines());
123
124 // Check we get the same instruction set features using /proc/cpuinfo.
125 std::unique_ptr<const InstructionSetFeatures> cpuinfo_features(
126 InstructionSetFeatures::FromCpuInfo());
127 EXPECT_TRUE(cpuinfo_features->HasAtLeast(instruction_set_features.get()))
128 << "CPU Info features: " << *cpuinfo_features.get()
129 << "\nFeatures from build: " << *instruction_set_features.get();
130 }
131 #endif
132
133 #ifndef ART_TARGET_ANDROID
134 TEST(InstructionSetFeaturesTest, HostFeaturesFromCppDefines) {
135 std::string error_msg;
136 std::unique_ptr<const InstructionSetFeatures> default_features(
137 InstructionSetFeatures::FromVariant(kRuntimeISA, "default", &error_msg));
138 ASSERT_TRUE(error_msg.empty());
139
140 std::unique_ptr<const InstructionSetFeatures> cpp_features(
141 InstructionSetFeatures::FromCppDefines());
142 EXPECT_TRUE(cpp_features->HasAtLeast(default_features.get()))
143 << "Default variant features: " << *default_features.get()
144 << "\nFeatures from build: " << *cpp_features.get();
145 }
146 #endif
147
148 #if defined(__arm__)
149 TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromHwcap) {
150 LOG(WARNING) << "Test disabled due to buggy ARM kernels";
151 #else
152 TEST(InstructionSetFeaturesTest, FeaturesFromHwcap) {
153 #endif
154 // Take the default set of instruction features from the build.
155 std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
156 InstructionSetFeatures::FromCppDefines());
157
158 // Check we get the same instruction set features using AT_HWCAP.
159 std::unique_ptr<const InstructionSetFeatures> hwcap_features(
160 InstructionSetFeatures::FromHwcap());
161 EXPECT_TRUE(hwcap_features->HasAtLeast(instruction_set_features.get()))
162 << "Hwcap features: " << *hwcap_features.get()
163 << "\nFeatures from build: " << *instruction_set_features.get();
164 }
165
166 TEST(InstructionSetFeaturesTest, FeaturesFromAssembly) {
167 // Take the default set of instruction features from the build.
168 std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
169 InstructionSetFeatures::FromCppDefines());
170
171 // Check we get the same instruction set features using assembly tests.
172 std::unique_ptr<const InstructionSetFeatures> assembly_features(
173 InstructionSetFeatures::FromAssembly());
174 EXPECT_TRUE(assembly_features->HasAtLeast(instruction_set_features.get()))
175 << "Assembly features: " << *assembly_features.get()
176 << "\nFeatures from build: " << *instruction_set_features.get();
177 }
178
179 TEST(InstructionSetFeaturesTest, FeaturestFromCpuFeatures) {
180 // Take the default set of instruction features from the build.
181 std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
182 InstructionSetFeatures::FromCppDefines());
183
184 // Check we get the same instruction set features using the cpu_features library
185 std::unique_ptr<const InstructionSetFeatures> library_features(
186 InstructionSetFeatures::FromCpuFeatures());
187
188 EXPECT_TRUE(library_features->HasAtLeast(instruction_set_features.get()))
189 << "Library features: " << *library_features.get()
190 << "\nFeatures from build: " << *instruction_set_features.get();
191 }
192
193 TEST(InstructionSetFeaturesTest, FeaturesFromRuntimeDetection) {
194 if (!InstructionSetFeatures::IsRuntimeDetectionSupported()) {
195 EXPECT_EQ(InstructionSetFeatures::FromRuntimeDetection(), nullptr);
196 }
197 }
198
199 // The instruction set feature string must not contain 'default' together with
200 // other feature names.
201 //
202 // Test that InstructionSetFeatures::AddFeaturesFromString returns nullptr and
203 // an error is reported when the value 'default' is specified together
204 // with other feature names in an instruction set feature string.
205 TEST(InstructionSetFeaturesTest, AddFeaturesFromStringWithDefaultAndOtherNames) {
206 std::unique_ptr<const InstructionSetFeatures> cpp_defined_features(
207 InstructionSetFeatures::FromCppDefines());
208 std::vector<std::string> invalid_feature_strings = {
209 "a,default",
210 "default,a",
211 "a,default,b",
212 "a,b,default",
213 "default,a,b,c",
214 "a,b,default,c,d",
215 "a, default ",
216 " default , a",
217 "a, default , b",
218 "default,runtime"
219 };
220
221 for (const std::string& invalid_feature_string : invalid_feature_strings) {
222 std::string error_msg;
223 EXPECT_EQ(cpp_defined_features->AddFeaturesFromString(invalid_feature_string, &error_msg),
224 nullptr) << " Invalid feature string: '" << invalid_feature_string << "'";
225 EXPECT_EQ(error_msg,
226 "Specific instruction set feature(s) cannot be used when 'default' is used.");
227 }
228 }
229
230 // The instruction set feature string must not contain 'runtime' together with
231 // other feature names.
232 //
233 // Test that InstructionSetFeatures::AddFeaturesFromString returns nullptr and
234 // an error is reported when the value 'runtime' is specified together
235 // with other feature names in an instruction set feature string.
236 TEST(InstructionSetFeaturesTest, AddFeaturesFromStringWithRuntimeAndOtherNames) {
237 std::unique_ptr<const InstructionSetFeatures> cpp_defined_features(
238 InstructionSetFeatures::FromCppDefines());
239 std::vector<std::string> invalid_feature_strings = {
240 "a,runtime",
241 "runtime,a",
242 "a,runtime,b",
243 "a,b,runtime",
244 "runtime,a,b,c",
245 "a,b,runtime,c,d",
246 "a, runtime ",
247 " runtime , a",
248 "a, runtime , b",
249 "runtime,default"
250 };
251
252 for (const std::string& invalid_feature_string : invalid_feature_strings) {
253 std::string error_msg;
254 EXPECT_EQ(cpp_defined_features->AddFeaturesFromString(invalid_feature_string, &error_msg),
255 nullptr) << " Invalid feature string: '" << invalid_feature_string << "'";
256 EXPECT_EQ(error_msg,
257 "Specific instruction set feature(s) cannot be used when 'runtime' is used.");
258 }
259 }
260
261 // Spaces and multiple commas are ignores in a instruction set feature string.
262 //
263 // Test that a use of spaces and multiple commas with 'default' and 'runtime'
264 // does not cause errors.
265 TEST(InstructionSetFeaturesTest, AddFeaturesFromValidStringContainingDefaultOrRuntime) {
266 std::unique_ptr<const InstructionSetFeatures> cpp_defined_features(
267 InstructionSetFeatures::FromCppDefines());
268 std::vector<std::string> valid_feature_strings = {
269 "default",
270 ",,,default",
271 "default,,,,",
272 ",,,default,,,,",
273 "default, , , ",
274 " , , ,default",
275 " , , ,default, , , ",
276 " default , , , ",
277 ",,,runtime",
278 "runtime,,,,",
279 ",,,runtime,,,,",
280 "runtime, , , ",
281 " , , ,runtime",
282 " , , ,runtime, , , ",
283 " runtime , , , "
284 };
285 for (const std::string& valid_feature_string : valid_feature_strings) {
286 std::string error_msg;
287 EXPECT_NE(cpp_defined_features->AddFeaturesFromString(valid_feature_string, &error_msg),
288 nullptr) << " Valid feature string: '" << valid_feature_string << "'";
289 EXPECT_TRUE(error_msg.empty()) << error_msg;
290 }
291 }
292
293 // Spaces and multiple commas are ignores in a instruction set feature string.
294 //
295 // Test that a use of spaces and multiple commas without any feature names
296 // causes errors.
297 TEST(InstructionSetFeaturesTest, AddFeaturesFromInvalidStringWithoutFeatureNames) {
298 std::unique_ptr<const InstructionSetFeatures> cpp_defined_features(
299 InstructionSetFeatures::FromCppDefines());
300 std::vector<std::string> invalid_feature_strings = {
301 " ",
302 " ",
303 ",",
304 ",,",
305 " , , ,,,,,,",
306 "\t",
307 " \t ",
308 ",",
309 ",,",
310 " , , ,,,,,,"
311 };
312 for (const std::string& invalid_feature_string : invalid_feature_strings) {
313 std::string error_msg;
314 EXPECT_EQ(cpp_defined_features->AddFeaturesFromString(invalid_feature_string, &error_msg),
315 nullptr) << " Invalid feature string: '" << invalid_feature_string << "'";
316 EXPECT_EQ(error_msg, "No instruction set features specified");
317 }
318 }
319
320 TEST(InstructionSetFeaturesTest, AddFeaturesFromStringRuntime) {
321 std::unique_ptr<const InstructionSetFeatures> cpp_defined_features(
322 InstructionSetFeatures::FromCppDefines());
323 std::string error_msg;
324
325 const std::unique_ptr<const InstructionSetFeatures> features =
326 cpp_defined_features->AddFeaturesFromString("runtime", &error_msg);
327 EXPECT_NE(features, nullptr);
328 EXPECT_TRUE(error_msg.empty()) << error_msg;
329 if (!InstructionSetFeatures::IsRuntimeDetectionSupported()) {
330 EXPECT_TRUE(features->Equals(cpp_defined_features.get()));
331 }
332 }
333
334 } // namespace art
335