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, FeaturesFromRuntimeDetection) {
180 if (!InstructionSetFeatures::IsRuntimeDetectionSupported()) {
181 EXPECT_EQ(InstructionSetFeatures::FromRuntimeDetection(), nullptr);
182 }
183 }
184
185 // The instruction set feature string must not contain 'default' together with
186 // other feature names.
187 //
188 // Test that InstructionSetFeatures::AddFeaturesFromString returns nullptr and
189 // an error is reported when the value 'default' is specified together
190 // with other feature names in an instruction set feature string.
191 TEST(InstructionSetFeaturesTest, AddFeaturesFromStringWithDefaultAndOtherNames) {
192 std::unique_ptr<const InstructionSetFeatures> cpp_defined_features(
193 InstructionSetFeatures::FromCppDefines());
194 std::vector<std::string> invalid_feature_strings = {
195 "a,default",
196 "default,a",
197 "a,default,b",
198 "a,b,default",
199 "default,a,b,c",
200 "a,b,default,c,d",
201 "a, default ",
202 " default , a",
203 "a, default , b",
204 "default,runtime"
205 };
206
207 for (const std::string& invalid_feature_string : invalid_feature_strings) {
208 std::string error_msg;
209 EXPECT_EQ(cpp_defined_features->AddFeaturesFromString(invalid_feature_string, &error_msg),
210 nullptr) << " Invalid feature string: '" << invalid_feature_string << "'";
211 EXPECT_EQ(error_msg,
212 "Specific instruction set feature(s) cannot be used when 'default' is used.");
213 }
214 }
215
216 // The instruction set feature string must not contain 'runtime' together with
217 // other feature names.
218 //
219 // Test that InstructionSetFeatures::AddFeaturesFromString returns nullptr and
220 // an error is reported when the value 'runtime' is specified together
221 // with other feature names in an instruction set feature string.
222 TEST(InstructionSetFeaturesTest, AddFeaturesFromStringWithRuntimeAndOtherNames) {
223 std::unique_ptr<const InstructionSetFeatures> cpp_defined_features(
224 InstructionSetFeatures::FromCppDefines());
225 std::vector<std::string> invalid_feature_strings = {
226 "a,runtime",
227 "runtime,a",
228 "a,runtime,b",
229 "a,b,runtime",
230 "runtime,a,b,c",
231 "a,b,runtime,c,d",
232 "a, runtime ",
233 " runtime , a",
234 "a, runtime , b",
235 "runtime,default"
236 };
237
238 for (const std::string& invalid_feature_string : invalid_feature_strings) {
239 std::string error_msg;
240 EXPECT_EQ(cpp_defined_features->AddFeaturesFromString(invalid_feature_string, &error_msg),
241 nullptr) << " Invalid feature string: '" << invalid_feature_string << "'";
242 EXPECT_EQ(error_msg,
243 "Specific instruction set feature(s) cannot be used when 'runtime' is used.");
244 }
245 }
246
247 // Spaces and multiple commas are ignores in a instruction set feature string.
248 //
249 // Test that a use of spaces and multiple commas with 'default' and 'runtime'
250 // does not cause errors.
251 TEST(InstructionSetFeaturesTest, AddFeaturesFromValidStringContainingDefaultOrRuntime) {
252 std::unique_ptr<const InstructionSetFeatures> cpp_defined_features(
253 InstructionSetFeatures::FromCppDefines());
254 std::vector<std::string> valid_feature_strings = {
255 "default",
256 ",,,default",
257 "default,,,,",
258 ",,,default,,,,",
259 "default, , , ",
260 " , , ,default",
261 " , , ,default, , , ",
262 " default , , , ",
263 ",,,runtime",
264 "runtime,,,,",
265 ",,,runtime,,,,",
266 "runtime, , , ",
267 " , , ,runtime",
268 " , , ,runtime, , , ",
269 " runtime , , , "
270 };
271 for (const std::string& valid_feature_string : valid_feature_strings) {
272 std::string error_msg;
273 EXPECT_NE(cpp_defined_features->AddFeaturesFromString(valid_feature_string, &error_msg),
274 nullptr) << " Valid feature string: '" << valid_feature_string << "'";
275 EXPECT_TRUE(error_msg.empty()) << error_msg;
276 }
277 }
278
279 // Spaces and multiple commas are ignores in a instruction set feature string.
280 //
281 // Test that a use of spaces and multiple commas without any feature names
282 // causes errors.
283 TEST(InstructionSetFeaturesTest, AddFeaturesFromInvalidStringWithoutFeatureNames) {
284 std::unique_ptr<const InstructionSetFeatures> cpp_defined_features(
285 InstructionSetFeatures::FromCppDefines());
286 std::vector<std::string> invalid_feature_strings = {
287 " ",
288 " ",
289 ",",
290 ",,",
291 " , , ,,,,,,",
292 "\t",
293 " \t ",
294 ",",
295 ",,",
296 " , , ,,,,,,"
297 };
298 for (const std::string& invalid_feature_string : invalid_feature_strings) {
299 std::string error_msg;
300 EXPECT_EQ(cpp_defined_features->AddFeaturesFromString(invalid_feature_string, &error_msg),
301 nullptr) << " Invalid feature string: '" << invalid_feature_string << "'";
302 EXPECT_EQ(error_msg, "No instruction set features specified");
303 }
304 }
305
306 TEST(InstructionSetFeaturesTest, AddFeaturesFromStringRuntime) {
307 std::unique_ptr<const InstructionSetFeatures> cpp_defined_features(
308 InstructionSetFeatures::FromCppDefines());
309 std::string error_msg;
310
311 const std::unique_ptr<const InstructionSetFeatures> features =
312 cpp_defined_features->AddFeaturesFromString("runtime", &error_msg);
313 EXPECT_NE(features, nullptr);
314 EXPECT_TRUE(error_msg.empty()) << error_msg;
315 if (!InstructionSetFeatures::IsRuntimeDetectionSupported()) {
316 EXPECT_TRUE(features->Equals(cpp_defined_features.get()));
317 }
318 }
319
320 } // namespace art
321