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