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