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 "instruction_set_features.h"
20
21 #include <gtest/gtest.h>
22
23 #ifdef ART_TARGET_ANDROID
24 #include <android-base/properties.h>
25 #endif
26
27 #include <android-base/logging.h>
28 #include <android-base/stringprintf.h>
29
30 namespace art {
31
32 #ifdef ART_TARGET_ANDROID
33
34 using android::base::StringPrintf;
35
36 #if defined(__aarch64__)
TEST(InstructionSetFeaturesTest,DISABLED_FeaturesFromSystemPropertyVariant)37 TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromSystemPropertyVariant) {
38 LOG(WARNING) << "Test disabled due to no CPP define for A53 erratum 835769";
39 #else
40 TEST(InstructionSetFeaturesTest, FeaturesFromSystemPropertyVariant) {
41 #endif
42 // Take the default set of instruction features from the build.
43 std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
44 InstructionSetFeatures::FromCppDefines());
45
46 // Read the variant property.
47 std::string key = StringPrintf("dalvik.vm.isa.%s.variant", GetInstructionSetString(kRuntimeISA));
48 std::string dex2oat_isa_variant = android::base::GetProperty(key, "");
49 if (!dex2oat_isa_variant.empty()) {
50 // Use features from property to build InstructionSetFeatures and check against build's
51 // features.
52 std::string error_msg;
53 std::unique_ptr<const InstructionSetFeatures> property_features(
54 InstructionSetFeatures::FromVariant(kRuntimeISA, dex2oat_isa_variant, &error_msg));
55 ASSERT_TRUE(property_features.get() != nullptr) << error_msg;
56
57 EXPECT_TRUE(property_features->HasAtLeast(instruction_set_features.get()))
58 << "System property features: " << *property_features.get()
59 << "\nFeatures from build: " << *instruction_set_features.get();
60 }
61 }
62
63 #if defined(__aarch64__)
64 TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromSystemPropertyString) {
65 LOG(WARNING) << "Test disabled due to no CPP define for A53 erratum 835769";
66 #else
67 TEST(InstructionSetFeaturesTest, FeaturesFromSystemPropertyString) {
68 #endif
69 // Take the default set of instruction features from the build.
70 std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
71 InstructionSetFeatures::FromCppDefines());
72
73 // Read the variant property.
74 std::string variant_key = StringPrintf("dalvik.vm.isa.%s.variant",
75 GetInstructionSetString(kRuntimeISA));
76 std::string dex2oat_isa_variant = android::base::GetProperty(variant_key, "");
77 if (!dex2oat_isa_variant.empty()) {
78 // Read the features property.
79 std::string features_key = StringPrintf("dalvik.vm.isa.%s.features",
80 GetInstructionSetString(kRuntimeISA));
81 std::string dex2oat_isa_features = android::base::GetProperty(features_key, "");
82 if (!dex2oat_isa_features.empty()) {
83 // Use features from property to build InstructionSetFeatures and check against build's
84 // features.
85 std::string error_msg;
86 std::unique_ptr<const InstructionSetFeatures> base_features(
87 InstructionSetFeatures::FromVariant(kRuntimeISA, dex2oat_isa_variant, &error_msg));
88 ASSERT_TRUE(base_features.get() != nullptr) << error_msg;
89
90 std::unique_ptr<const InstructionSetFeatures> property_features(
91 base_features->AddFeaturesFromString(dex2oat_isa_features, &error_msg));
92 ASSERT_TRUE(property_features.get() != nullptr) << error_msg;
93
94 EXPECT_TRUE(property_features->HasAtLeast(instruction_set_features.get()))
95 << "System property features: " << *property_features.get()
96 << "\nFeatures from build: " << *instruction_set_features.get();
97 }
98 }
99 }
100
101 #if defined(__arm__)
102 TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromCpuInfo) {
103 LOG(WARNING) << "Test disabled due to buggy ARM kernels";
104 #else
105 TEST(InstructionSetFeaturesTest, FeaturesFromCpuInfo) {
106 #endif
107 // Take the default set of instruction features from the build.
108 std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
109 InstructionSetFeatures::FromCppDefines());
110
111 // Check we get the same instruction set features using /proc/cpuinfo.
112 std::unique_ptr<const InstructionSetFeatures> cpuinfo_features(
113 InstructionSetFeatures::FromCpuInfo());
114 EXPECT_TRUE(cpuinfo_features->HasAtLeast(instruction_set_features.get()))
115 << "CPU Info features: " << *cpuinfo_features.get()
116 << "\nFeatures from build: " << *instruction_set_features.get();
117 }
118 #endif
119
120 #ifndef ART_TARGET_ANDROID
121 TEST(InstructionSetFeaturesTest, HostFeaturesFromCppDefines) {
122 std::string error_msg;
123 std::unique_ptr<const InstructionSetFeatures> default_features(
124 InstructionSetFeatures::FromVariant(kRuntimeISA, "default", &error_msg));
125 ASSERT_TRUE(error_msg.empty());
126
127 std::unique_ptr<const InstructionSetFeatures> cpp_features(
128 InstructionSetFeatures::FromCppDefines());
129 EXPECT_TRUE(cpp_features->HasAtLeast(default_features.get()))
130 << "Default variant features: " << *default_features.get()
131 << "\nFeatures from build: " << *cpp_features.get();
132 }
133 #endif
134
135 #if defined(__arm__)
136 TEST(InstructionSetFeaturesTest, DISABLED_FeaturesFromHwcap) {
137 LOG(WARNING) << "Test disabled due to buggy ARM kernels";
138 #else
139 TEST(InstructionSetFeaturesTest, FeaturesFromHwcap) {
140 #endif
141 // Take the default set of instruction features from the build.
142 std::unique_ptr<const InstructionSetFeatures> instruction_set_features(
143 InstructionSetFeatures::FromCppDefines());
144
145 // Check we get the same instruction set features using AT_HWCAP.
146 std::unique_ptr<const InstructionSetFeatures> hwcap_features(
147 InstructionSetFeatures::FromHwcap());
148 EXPECT_TRUE(hwcap_features->HasAtLeast(instruction_set_features.get()))
149 << "Hwcap features: " << *hwcap_features.get()
150 << "\nFeatures from build: " << *instruction_set_features.get();
151 }
152
153 TEST(InstructionSetFeaturesTest, FeaturesFromAssembly) {
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 assembly tests.
159 std::unique_ptr<const InstructionSetFeatures> assembly_features(
160 InstructionSetFeatures::FromAssembly());
161 EXPECT_TRUE(assembly_features->HasAtLeast(instruction_set_features.get()))
162 << "Assembly features: " << *assembly_features.get()
163 << "\nFeatures from build: " << *instruction_set_features.get();
164 }
165
166 TEST(InstructionSetFeaturesTest, FeaturesFromRuntimeDetection) {
167 if (!InstructionSetFeatures::IsRuntimeDetectionSupported()) {
168 EXPECT_EQ(InstructionSetFeatures::FromRuntimeDetection(), nullptr);
169 }
170 }
171
172 // The instruction set feature string must not contain 'default' together with
173 // other feature names.
174 //
175 // Test that InstructionSetFeatures::AddFeaturesFromString returns nullptr and
176 // an error is reported when the value 'default' is specified together
177 // with other feature names in an instruction set feature string.
178 TEST(InstructionSetFeaturesTest, AddFeaturesFromStringWithDefaultAndOtherNames) {
179 std::unique_ptr<const InstructionSetFeatures> cpp_defined_features(
180 InstructionSetFeatures::FromCppDefines());
181 std::vector<std::string> invalid_feature_strings = {
182 "a,default",
183 "default,a",
184 "a,default,b",
185 "a,b,default",
186 "default,a,b,c",
187 "a,b,default,c,d",
188 "a, default ",
189 " default , a",
190 "a, default , b",
191 "default,runtime"
192 };
193
194 for (const std::string& invalid_feature_string : invalid_feature_strings) {
195 std::string error_msg;
196 EXPECT_EQ(cpp_defined_features->AddFeaturesFromString(invalid_feature_string, &error_msg),
197 nullptr) << " Invalid feature string: '" << invalid_feature_string << "'";
198 EXPECT_EQ(error_msg,
199 "Specific instruction set feature(s) cannot be used when 'default' is used.");
200 }
201 }
202
203 // The instruction set feature string must not contain 'runtime' together with
204 // other feature names.
205 //
206 // Test that InstructionSetFeatures::AddFeaturesFromString returns nullptr and
207 // an error is reported when the value 'runtime' is specified together
208 // with other feature names in an instruction set feature string.
209 TEST(InstructionSetFeaturesTest, AddFeaturesFromStringWithRuntimeAndOtherNames) {
210 std::unique_ptr<const InstructionSetFeatures> cpp_defined_features(
211 InstructionSetFeatures::FromCppDefines());
212 std::vector<std::string> invalid_feature_strings = {
213 "a,runtime",
214 "runtime,a",
215 "a,runtime,b",
216 "a,b,runtime",
217 "runtime,a,b,c",
218 "a,b,runtime,c,d",
219 "a, runtime ",
220 " runtime , a",
221 "a, runtime , b",
222 "runtime,default"
223 };
224
225 for (const std::string& invalid_feature_string : invalid_feature_strings) {
226 std::string error_msg;
227 EXPECT_EQ(cpp_defined_features->AddFeaturesFromString(invalid_feature_string, &error_msg),
228 nullptr) << " Invalid feature string: '" << invalid_feature_string << "'";
229 EXPECT_EQ(error_msg,
230 "Specific instruction set feature(s) cannot be used when 'runtime' is used.");
231 }
232 }
233
234 // Spaces and multiple commas are ignores in a instruction set feature string.
235 //
236 // Test that a use of spaces and multiple commas with 'default' and 'runtime'
237 // does not cause errors.
238 TEST(InstructionSetFeaturesTest, AddFeaturesFromValidStringContainingDefaultOrRuntime) {
239 std::unique_ptr<const InstructionSetFeatures> cpp_defined_features(
240 InstructionSetFeatures::FromCppDefines());
241 std::vector<std::string> valid_feature_strings = {
242 "default",
243 ",,,default",
244 "default,,,,",
245 ",,,default,,,,",
246 "default, , , ",
247 " , , ,default",
248 " , , ,default, , , ",
249 " default , , , ",
250 ",,,runtime",
251 "runtime,,,,",
252 ",,,runtime,,,,",
253 "runtime, , , ",
254 " , , ,runtime",
255 " , , ,runtime, , , ",
256 " runtime , , , "
257 };
258 for (const std::string& valid_feature_string : valid_feature_strings) {
259 std::string error_msg;
260 EXPECT_NE(cpp_defined_features->AddFeaturesFromString(valid_feature_string, &error_msg),
261 nullptr) << " Valid feature string: '" << valid_feature_string << "'";
262 EXPECT_TRUE(error_msg.empty()) << error_msg;
263 }
264 }
265
266 // Spaces and multiple commas are ignores in a instruction set feature string.
267 //
268 // Test that a use of spaces and multiple commas without any feature names
269 // causes errors.
270 TEST(InstructionSetFeaturesTest, AddFeaturesFromInvalidStringWithoutFeatureNames) {
271 std::unique_ptr<const InstructionSetFeatures> cpp_defined_features(
272 InstructionSetFeatures::FromCppDefines());
273 std::vector<std::string> invalid_feature_strings = {
274 " ",
275 " ",
276 ",",
277 ",,",
278 " , , ,,,,,,",
279 "\t",
280 " \t ",
281 ",",
282 ",,",
283 " , , ,,,,,,"
284 };
285 for (const std::string& invalid_feature_string : invalid_feature_strings) {
286 std::string error_msg;
287 EXPECT_EQ(cpp_defined_features->AddFeaturesFromString(invalid_feature_string, &error_msg),
288 nullptr) << " Invalid feature string: '" << invalid_feature_string << "'";
289 EXPECT_EQ(error_msg, "No instruction set features specified");
290 }
291 }
292
293 TEST(InstructionSetFeaturesTest, AddFeaturesFromStringRuntime) {
294 std::unique_ptr<const InstructionSetFeatures> cpp_defined_features(
295 InstructionSetFeatures::FromCppDefines());
296 std::string error_msg;
297
298 const std::unique_ptr<const InstructionSetFeatures> features =
299 cpp_defined_features->AddFeaturesFromString("runtime", &error_msg);
300 EXPECT_NE(features, nullptr);
301 EXPECT_TRUE(error_msg.empty()) << error_msg;
302 if (!InstructionSetFeatures::IsRuntimeDetectionSupported()) {
303 EXPECT_TRUE(features->Equals(cpp_defined_features.get()));
304 }
305 }
306
307 } // namespace art
308