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