| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include <fcntl.h> | 5 #include <fcntl.h> |
| 6 #include <launchpad/launchpad.h> | 6 #include <launchpad/launchpad.h> |
| 7 #include <magenta/syscalls.h> | 7 #include <magenta/syscalls.h> |
| 8 #include <mxio/util.h> | 8 #include <mxio/util.h> |
| 9 #include <pthread.h> |
| 10 #include <runtime/sysinfo.h> |
| 9 #include <stdbool.h> | 11 #include <stdbool.h> |
| 10 #include <stdio.h> | 12 #include <stdio.h> |
| 11 #include <stdlib.h> | 13 #include <stdlib.h> |
| 12 #include <string.h> | 14 #include <string.h> |
| 13 #include <unistd.h> | 15 #include <unistd.h> |
| 14 | 16 |
| 15 // This program runs Dart VM unit tests. The Dart VM unit tests are contained | 17 // This program runs Dart VM unit tests. The Dart VM unit tests are contained |
| 16 // in a separate binary whose location is defined in kRunVmTestsPath below. | 18 // in a separate binary whose location is defined in kRunVmTestsPath below. |
| 17 // That program accepts a command line argument --list to list all the available | 19 // That program accepts a command line argument --list to list all the available |
| 18 // tests, or the name of a single test to run. This program accepts a single | 20 // tests, or the name of a single test to run. This program accepts a single |
| 19 // command line argument which is the path to a file containing a list of tests | 21 // command line argument which is the path to a file containing a list of tests |
| 20 // to run, one per line. | 22 // to run, one per line. |
| 21 | 23 |
| 22 const char* kRunVmTestsPath = "/boot/bin/dart_vm_tests"; | 24 const char* kRunVmTestsPath = "/boot/bin/dart_vm_tests"; |
| 23 | 25 |
| 24 // Tests that are invalid, wedge, or cause panics. | 26 // Tests that are invalid, wedge, or cause panics. |
| 25 const char* kSkip[] = { | 27 const char* kSkip[] = { |
| 26 // These expect a file to exist that we aren't putting in the image. | 28 // These expect a file to exist that we aren't putting in the image. |
| 27 "Read", | 29 "Read", |
| 28 "FileLength", | 30 "FileLength", |
| 29 "FilePosition", | 31 "FilePosition", |
| 30 // Hangs. | 32 // Hangs. |
| 31 "ArrayLengthMaxElements", | 33 "ArrayLengthMaxElements", |
| 32 "Int8ListLengthMaxElements", | 34 "Int8ListLengthMaxElements", |
| 33 "ThreadPool_WorkerShutdown", | |
| 34 "LargeMap", | 35 "LargeMap", |
| 35 "CompileFunctionOnHelperThread", | 36 "CompileFunctionOnHelperThread", |
| 36 // The profiler is turned off. | 37 // The profiler is turned off. |
| 37 "Profiler_AllocationSampleTest", | 38 "Profiler_AllocationSampleTest", |
| 38 "Profiler_ArrayAllocation", | 39 "Profiler_ArrayAllocation", |
| 39 "Profiler_BasicSourcePosition", | 40 "Profiler_BasicSourcePosition", |
| 40 "Profiler_BasicSourcePositionOptimized", | 41 "Profiler_BasicSourcePositionOptimized", |
| 41 "Profiler_BinaryOperatorSourcePosition", | 42 "Profiler_BinaryOperatorSourcePosition", |
| 42 "Profiler_BinaryOperatorSourcePositionOptimized", | 43 "Profiler_BinaryOperatorSourcePositionOptimized", |
| 43 "Profiler_ChainedSamples", | 44 "Profiler_ChainedSamples", |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 76 "IsolateReload_PendingStaticCall_DefinedToNSM", | 77 "IsolateReload_PendingStaticCall_DefinedToNSM", |
| 77 "IsolateReload_PendingStaticCall_NSMToDefined", | 78 "IsolateReload_PendingStaticCall_NSMToDefined", |
| 78 "ArrayNew_Overflow_Crash", | 79 "ArrayNew_Overflow_Crash", |
| 79 "AllocGeneric_Overflow", | 80 "AllocGeneric_Overflow", |
| 80 "CodeImmutability", | 81 "CodeImmutability", |
| 81 "SNPrint_BadArgs", | 82 "SNPrint_BadArgs", |
| 82 }; | 83 }; |
| 83 | 84 |
| 84 // Bugs to fix, or things that are not yet impelemnted. | 85 // Bugs to fix, or things that are not yet impelemnted. |
| 85 const char* kBugs[] = { | 86 const char* kBugs[] = { |
| 86 // pthreads not using specified stack size. | 87 // pthreads not using specified stack size? |
| 87 "StackOverflowStacktraceInfo", | 88 "StackOverflowStacktraceInfo", |
| 88 // Needs OS::GetCurrentThreadCPUMicros. | 89 // Needs OS::GetCurrentThreadCPUMicros. |
| 89 "Timeline_Dart_TimelineDuration", | |
| 90 "Timeline_Dart_TimelineInstant" | |
| 91 "Timeline_Dart_TimelineAsyncDisabled", | |
| 92 "Timeline_Dart_TimelineAsync", | |
| 93 "Timeline_Dart_TimelineGetTrace", | 90 "Timeline_Dart_TimelineGetTrace", |
| 94 "Timeline_Dart_TimelineGetTraceOnlyDartEvents", | 91 "Timeline_Dart_TimelineGetTraceOnlyDartEvents", |
| 95 "Timeline_Dart_TimelineGetTraceWithDartEvents", | 92 "Timeline_Dart_TimelineGetTraceWithDartEvents", |
| 96 "Timeline_Dart_TimelineGetTraceGlobalOverride", | 93 "Timeline_Dart_TimelineGetTraceGlobalOverride", |
| 97 "Timeline_Dart_GlobalTimelineGetTrace", | 94 "Timeline_Dart_GlobalTimelineGetTrace", |
| 98 "Timeline_Dart_GlobalTimelineGetTrace_Threaded", | 95 "Timeline_Dart_GlobalTimelineGetTrace_Threaded", |
| 99 "TimelineEventDuration", | 96 "TimelineEventDuration", |
| 100 "TimelineEventDurationPrintJSON", | 97 "TimelineEventDurationPrintJSON", |
| 101 "TimelineEventArguments", | 98 "TimelineEventArguments", |
| 102 "TimelineEventArgumentsPrintJSON", | 99 "TimelineEventArgumentsPrintJSON", |
| 103 "TimelineEventBufferPrintJSON", | |
| 104 "TimelineEventCallbackRecorderBasic", | 100 "TimelineEventCallbackRecorderBasic", |
| 105 "TimelineAnalysis_ThreadBlockCount", | 101 "TimelineAnalysis_ThreadBlockCount", |
| 106 "TimelineRingRecorderJSONOrder", | 102 "TimelineRingRecorderJSONOrder", |
| 107 "TimelinePauses_BeginEnd", | 103 "TimelinePauses_BeginEnd", |
| 108 // Crash. | |
| 109 "FindCodeObject", | |
| 110 // Needs NativeSymbolResolver | 104 // Needs NativeSymbolResolver |
| 111 "Service_PersistentHandles", | 105 "Service_PersistentHandles", |
| 112 // Need to investigate: | 106 // Need to investigate: |
| 107 "FindCodeObject", |
| 113 "ThreadIterator_AddFindRemove", | 108 "ThreadIterator_AddFindRemove", |
| 109 "PrintJSON", |
| 110 "SourceReport_Coverage_AllFunctions_ForceCompile", |
| 114 }; | 111 }; |
| 115 | 112 |
| 116 | 113 |
| 117 static bool contains(const char** list, intptr_t len, const char* str) { | 114 static bool contains(const char** list, intptr_t len, const char* str) { |
| 118 for (intptr_t i = 0; i < len; i++) { | 115 for (intptr_t i = 0; i < len; i++) { |
| 119 if (strcmp(list[i], str) == 0) { | 116 if (strcmp(list[i], str) == 0) { |
| 120 return true; | 117 return true; |
| 121 } | 118 } |
| 122 } | 119 } |
| 123 return false; | 120 return false; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 142 | 139 |
| 143 | 140 |
| 144 static int run_test(const char* test_name) { | 141 static int run_test(const char* test_name) { |
| 145 const intptr_t kArgc = 2; | 142 const intptr_t kArgc = 2; |
| 146 const char* argv[3]; | 143 const char* argv[3]; |
| 147 argv[0] = kRunVmTestsPath; | 144 argv[0] = kRunVmTestsPath; |
| 148 argv[1] = test_name; | 145 argv[1] = test_name; |
| 149 | 146 |
| 150 mx_handle_t p = launchpad_launch(argv[0], kArgc, argv); | 147 mx_handle_t p = launchpad_launch(argv[0], kArgc, argv); |
| 151 if (p < 0) { | 148 if (p < 0) { |
| 152 printf("process failed to start\n"); | 149 fprintf(stderr, "process failed to start\n"); |
| 153 return -1; | 150 return -1; |
| 154 } | 151 } |
| 155 | 152 |
| 156 mx_signals_state_t state; | 153 mx_signals_state_t state; |
| 157 mx_status_t r = mx_handle_wait_one( | 154 mx_status_t r = mx_handle_wait_one( |
| 158 p, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, &state); | 155 p, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, &state); |
| 159 if (r != NO_ERROR) { | 156 if (r != NO_ERROR) { |
| 160 printf("[process(%x): wait failed? %d]\n", p, r); | 157 fprintf(stderr, "[process(%x): wait failed? %d]\n", p, r); |
| 161 return -1; | 158 return -1; |
| 162 } | 159 } |
| 163 | 160 |
| 164 mx_process_info_t proc_info; | 161 mx_process_info_t proc_info; |
| 165 mx_ssize_t ret = mx_handle_get_info( | 162 mx_ssize_t ret = mx_handle_get_info( |
| 166 p, MX_INFO_PROCESS, &proc_info, sizeof(proc_info)); | 163 p, MX_INFO_PROCESS, &proc_info, sizeof(proc_info)); |
| 167 if (ret != sizeof(proc_info)) { | 164 if (ret != sizeof(proc_info)) { |
| 168 printf("[process(%x): handle_get_info failed? %ld]\n", p, ret); | 165 fprintf(stderr, "[process(%x): handle_get_info failed? %ld]\n", p, ret); |
| 169 return -1; | 166 return -1; |
| 170 } | 167 } |
| 171 | 168 |
| 172 mx_handle_close(p); | 169 mx_handle_close(p); |
| 173 return proc_info.return_code; | 170 return proc_info.return_code; |
| 174 } | 171 } |
| 175 | 172 |
| 176 | 173 |
| 174 static void handle_result(intptr_t result, const char* test) { |
| 175 if (result != 0) { |
| 176 if (!isExpectFail(test) && !isBug(test)) { |
| 177 printf("******** Test %s FAILED\n", test); |
| 178 } |
| 179 } else { |
| 180 if (isExpectFail(test)) { |
| 181 printf("******** Test %s is expected to fail, but PASSED\n", test); |
| 182 } |
| 183 if (isBug(test)) { |
| 184 printf("******** Test %s is marked as a bug, but PASSED\n", test); |
| 185 } |
| 186 } |
| 187 } |
| 188 |
| 189 |
| 190 typedef struct { |
| 191 pthread_mutex_t* test_list_lock; |
| 192 char** test_list; |
| 193 intptr_t test_list_length; |
| 194 intptr_t* test_list_index; |
| 195 } runner_args_t; |
| 196 |
| 197 |
| 198 static void* test_runner_thread(void* arg) { |
| 199 runner_args_t* args = reinterpret_cast<runner_args_t*>(arg); |
| 200 |
| 201 pthread_mutex_lock(args->test_list_lock); |
| 202 while (*args->test_list_index < args->test_list_length) { |
| 203 const intptr_t index = *args->test_list_index; |
| 204 *args->test_list_index = index + 1; |
| 205 pthread_mutex_unlock(args->test_list_lock); |
| 206 const char* test = args->test_list[index]; |
| 207 handle_result(run_test(test), test); |
| 208 pthread_mutex_lock(args->test_list_lock); |
| 209 } |
| 210 pthread_mutex_unlock(args->test_list_lock); |
| 211 |
| 212 return NULL; |
| 213 } |
| 214 |
| 215 |
| 177 static void trim(char* line) { | 216 static void trim(char* line) { |
| 178 const intptr_t line_len = strlen(line); | 217 const intptr_t line_len = strlen(line); |
| 179 if (line[line_len - 1] == '\n') { | 218 if (line[line_len - 1] == '\n') { |
| 180 line[line_len - 1] = '\0'; | 219 line[line_len - 1] = '\0'; |
| 181 } | 220 } |
| 182 } | 221 } |
| 183 | 222 |
| 184 | 223 |
| 185 static bool should_run(const char* test) { | 224 static bool should_run(const char* test) { |
| 186 return !(test[0] == '#') && !isSkip(test); | 225 return !(test[0] == '#') && !isSkip(test); |
| 187 } | 226 } |
| 188 | 227 |
| 189 | 228 |
| 190 static void handle_result(intptr_t result, const char* test) { | 229 static intptr_t count_lines(FILE* fp) { |
| 191 if (result != 0) { | 230 intptr_t lines = 0; |
| 192 if (!isExpectFail(test) && !isBug(test)) { | 231 |
| 193 printf("******** Test %s FAILED\n", test); | 232 // Make sure we're at the beginning of the file. |
| 194 } | 233 rewind(fp); |
| 195 } else { | 234 |
| 196 if (isExpectFail(test)) { | 235 intptr_t ch; |
| 197 printf("******** Test %s is expected to fail, but PASSED\n", test); | 236 while ((ch = fgetc(fp)) != EOF) { |
| 198 } | 237 if (ch == '\n') { |
| 199 if (isBug(test)) { | 238 lines++; |
| 200 printf("******** Test %s is marked as a bug, but PASSED\n", test); | |
| 201 } | 239 } |
| 202 } | 240 } |
| 241 |
| 242 rewind(fp); |
| 243 return lines; |
| 203 } | 244 } |
| 204 | 245 |
| 205 | 246 |
| 247 static intptr_t read_lines(FILE* fp, char** lines, intptr_t lines_length) { |
| 248 char* test = NULL; |
| 249 size_t len = 0; |
| 250 ssize_t read; |
| 251 intptr_t i = 0; |
| 252 while (((read = getline(&test, &len, fp)) != -1) && (i < lines_length)) { |
| 253 trim(test); |
| 254 if (!should_run(test)) { |
| 255 continue; |
| 256 } |
| 257 lines[i] = strdup(test); |
| 258 i++; |
| 259 } |
| 260 |
| 261 if (test != NULL) { |
| 262 free(test); |
| 263 } |
| 264 return i; |
| 265 } |
| 266 |
| 267 |
| 206 int main(int argc, char** argv) { | 268 int main(int argc, char** argv) { |
| 207 if (argc <= 1) { | 269 if (argc <= 1) { |
| 208 fprintf(stderr, "Pass the path to a file containing the list of tests\n"); | 270 fprintf(stderr, "Pass the path to a file containing the list of tests\n"); |
| 209 return -1; | 271 return -1; |
| 210 } | 272 } |
| 211 const char* tests_path = argv[1]; | 273 const char* tests_path = argv[1]; |
| 212 | 274 |
| 213 FILE* fp = fopen(tests_path, "r"); | 275 FILE* fp = fopen(tests_path, "r"); |
| 214 if (fp == NULL) { | 276 if (fp == NULL) { |
| 215 fprintf(stderr, "Failed to read the file: %s\n", tests_path); | 277 fprintf(stderr, "Failed to read the file: %s\n", tests_path); |
| 216 return -1; | 278 return -1; |
| 217 } | 279 } |
| 218 | 280 |
| 219 char* test = NULL; | 281 intptr_t lines_count = count_lines(fp); |
| 220 size_t len = 0; | 282 char** test_list = |
| 221 ssize_t read; | 283 reinterpret_cast<char**>(malloc(sizeof(*test_list) * lines_count)); |
| 222 while ((read = getline(&test, &len, fp)) != -1) { | 284 lines_count = read_lines(fp, test_list, lines_count); |
| 223 trim(test); | 285 fclose(fp); |
| 224 if (!should_run(test)) { | 286 |
| 225 continue; | 287 pthread_mutex_t args_mutex; |
| 226 } | 288 pthread_mutex_init(&args_mutex, NULL); |
| 227 intptr_t result = run_test(test); | 289 intptr_t test_list_index = 0; |
| 228 handle_result(result, test); | 290 runner_args_t args; |
| 291 args.test_list_lock = &args_mutex; |
| 292 args.test_list = test_list; |
| 293 args.test_list_length = lines_count; |
| 294 args.test_list_index = &test_list_index; |
| 295 |
| 296 const intptr_t num_cpus = mxr_get_nprocs_conf(); |
| 297 pthread_t* threads = |
| 298 reinterpret_cast<pthread_t*>(malloc(num_cpus * sizeof(pthread_t))); |
| 299 for (int i = 0; i < num_cpus; i++) { |
| 300 pthread_create(&threads[i], NULL, test_runner_thread, &args); |
| 229 } | 301 } |
| 230 | 302 |
| 231 fclose(fp); | 303 for (int i = 0; i < num_cpus; i++) { |
| 232 if (test != NULL) { | 304 pthread_join(threads[i], NULL); |
| 233 free(test); | |
| 234 } | 305 } |
| 306 |
| 307 free(threads); |
| 308 for (int i = 0; i < lines_count; i++) { |
| 309 free(test_list[i]); |
| 310 } |
| 311 free(test_list); |
| 312 pthread_mutex_destroy(&args_mutex); |
| 313 |
| 314 if (test_list_index != lines_count) { |
| 315 fprintf(stderr, "Failed to attempt all the tests!\n"); |
| 316 return -1; |
| 317 } |
| 318 |
| 235 return 0; | 319 return 0; |
| 236 } | 320 } |
| OLD | NEW |