Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(565)

Side by Side Diff: runtime/bin/run_vm_tests_fuchsia.cc

Issue 2238983003: Fuchsia: Improves run_vm_tests wrapper program. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Address comments, cleanup Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/bin/BUILD.gn ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 <launchpad/vmo.h>
7 #include <magenta/syscalls.h> 8 #include <magenta/syscalls.h>
8 #include <mxio/util.h> 9 #include <mxio/util.h>
9 #include <pthread.h> 10 #include <pthread.h>
11 #include <runtime/status.h>
12 #include <runtime/sysinfo.h>
10 #include <stdbool.h> 13 #include <stdbool.h>
11 #include <stdio.h> 14 #include <stdio.h>
12 #include <stdlib.h> 15 #include <stdlib.h>
13 #include <string.h> 16 #include <string.h>
14 #include <unistd.h> 17 #include <unistd.h>
15 18
16 // This program runs Dart VM unit tests. The Dart VM unit tests are contained 19 // This program runs Dart VM unit tests. The Dart VM unit tests are contained
17 // in a separate binary whose location is defined in kRunVmTestsPath below. 20 // in a separate binary whose location is defined in kRunVmTestsPath below.
18 // That program accepts a command line argument --list to list all the available 21 // That program accepts a command line argument --list to list all the available
19 // tests, or the name of a single test to run. This program accepts a single 22 // tests, or the name of a single test to run. This program grabs the list of
20 // command line argument which is the path to a file containing a list of tests 23 // tests, and then runs them.
21 // to run, one per line.
22 24
23 // TODO(zra): Make this a command line argument 25 // TODO(zra): Make this a command line argument
24 const char* kRunVmTestsPath = "/boot/bin/dart_vm_tests"; 26 const char* kRunVmTestsPath = "/boot/bin/dart_vm_tests";
25 27
26 // The simulator only has 512MB;
27 const intptr_t kOldGenHeapSizeMB = 256;
28
29 // Tests that are invalid, wedge, or cause panics. 28 // Tests that are invalid, wedge, or cause panics.
30 const char* kSkip[] = { 29 const char* kSkip[] = {
31 // These expect a file to exist that we aren't putting in the image. 30 // These expect a file to exist that we aren't putting in the image.
32 "Read", 31 "Read",
33 "FileLength", 32 "FileLength",
34 "FilePosition", 33 "FilePosition",
35 // Crash and then Hang. 34 // Crash and then Hang.
36 "ArrayLengthMaxElements", 35 "ArrayLengthMaxElements",
37 "Int8ListLengthMaxElements", 36 "Int8ListLengthMaxElements",
38 // Crashes in realloc. 37 // Crashes in realloc.
(...skipping 17 matching lines...) Expand all
56 "Profiler_SampleBufferWrapTest", 55 "Profiler_SampleBufferWrapTest",
57 "Profiler_SourcePosition", 56 "Profiler_SourcePosition",
58 "Profiler_SourcePositionOptimized", 57 "Profiler_SourcePositionOptimized",
59 "Profiler_StringAllocation", 58 "Profiler_StringAllocation",
60 "Profiler_StringInterpolation", 59 "Profiler_StringInterpolation",
61 "Profiler_ToggleRecordAllocation", 60 "Profiler_ToggleRecordAllocation",
62 "Profiler_TrivialRecordAllocation", 61 "Profiler_TrivialRecordAllocation",
63 "Profiler_TypedArrayAllocation", 62 "Profiler_TypedArrayAllocation",
64 "Profiler_GetSourceReport", 63 "Profiler_GetSourceReport",
65 "Service_Profile", 64 "Service_Profile",
66 // No realpath. 65 // No realpath, files not in image.
67 "Dart2JSCompilerStats", 66 "Dart2JSCompilerStats",
68 "Dart2JSCompileAll", 67 "Dart2JSCompileAll",
69 // Uses too much memory. 68 // Uses too much memory.
70 "PrintJSON", 69 "PrintJSON",
71 }; 70 };
72 71
73 // Expected to fail/crash. 72 // Expected to fail/crash.
74 const char* kExpectFail[] = { 73 const char* kExpectFail[] = {
75 "Fail0", 74 "Fail0",
76 "Fail1", 75 "Fail1",
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 return contains( 135 return contains(
137 kExpectFail, sizeof(kExpectFail) / sizeof(kExpectFail[0]), test); 136 kExpectFail, sizeof(kExpectFail) / sizeof(kExpectFail[0]), test);
138 } 137 }
139 138
140 139
141 static bool isBug(const char* test) { 140 static bool isBug(const char* test) {
142 return contains(kBugs, sizeof(kBugs) / sizeof(kBugs[0]), test); 141 return contains(kBugs, sizeof(kBugs) / sizeof(kBugs[0]), test);
143 } 142 }
144 143
145 144
146 static int run_test(const char* test_name) { 145 #define RETURN_IF_ERROR(status) \
147 const intptr_t kArgc = 3; 146 if (status < 0) { \
147 fprintf(stderr, "%s:%d: Magenta call failed: %s\n", \
148 __FILE__, __LINE__, mx_strstatus(static_cast<mx_status_t>(status))); \
149 fflush(0); \
150 return status; \
151 } \
152
153
154 // This is mostly taken from //magenta/system/uapp/mxsh with the addtion of
155 // launchpad_add_pipe calls to setup pipes for stdout and stderr.
156 static mx_status_t lp_setup(launchpad_t** lp_out, mx_handle_t binary_vmo,
157 int argc, const char* const* argv,
158 int *stdout_out, int *stderr_out) {
159 if ((lp_out == NULL) || (stdout_out == NULL) || (stderr_out == NULL)) {
160 return ERR_INVALID_ARGS;
161 }
162 launchpad_t* lp;
163 mx_status_t status;
164 status = launchpad_create(argv[0], &lp);
165 RETURN_IF_ERROR(status);
166 status = launchpad_arguments(lp, argc, argv);
167 RETURN_IF_ERROR(status);
168 status = launchpad_clone_mxio_root(lp);
169 RETURN_IF_ERROR(status);
170 status = launchpad_add_pipe(lp, stdout_out, 1);
171 RETURN_IF_ERROR(status);
172 status = launchpad_add_pipe(lp, stderr_out, 2);
173 RETURN_IF_ERROR(status);
174 status = launchpad_elf_load(lp, binary_vmo);
175 RETURN_IF_ERROR(status);
176 *lp_out = lp;
177 return status;
178 }
179
180
181 // Start the test running and return file descriptors for the stdout and stderr
182 // pipes.
183 static mx_handle_t start_test(mx_handle_t binary_vmo, const char* test_name,
184 int* stdout_out, int* stderr_out) {
185 const intptr_t kArgc = 2;
148 const char* argv[kArgc]; 186 const char* argv[kArgc];
149 187
150 char old_gen_arg[64]; 188 argv[0] = kRunVmTestsPath;
151 snprintf(old_gen_arg, sizeof(old_gen_arg), "--old_gen_heap_size=%ld", 189 argv[1] = test_name;
152 kOldGenHeapSizeMB);
153 190
154 argv[0] = kRunVmTestsPath; 191 launchpad_t* lp = NULL;
155 argv[1] = old_gen_arg; 192 int stdout_pipe = -1;
156 argv[2] = test_name; 193 int stderr_pipe = -1;
194 mx_status_t status = lp_setup(
195 &lp, binary_vmo, kArgc, argv, &stdout_pipe, &stderr_pipe);
196 if (status != NO_ERROR) {
197 if (lp != NULL) {
198 launchpad_destroy(lp);
199 }
200 if (stdout_pipe != -1) {
201 close(stdout_pipe);
202 }
203 if (stderr_pipe != -1) {
204 close(stderr_pipe);
205 }
206 }
207 RETURN_IF_ERROR(status);
157 208
158 mx_handle_t p = launchpad_launch_mxio(argv[0], kArgc, argv); 209 mx_handle_t p = launchpad_start(lp);
210 launchpad_destroy(lp);
159 if (p < 0) { 211 if (p < 0) {
160 fprintf(stderr, "process failed to start\n"); 212 close(stdout_pipe);
161 return -1; 213 close(stderr_pipe);
162 } 214 }
215 RETURN_IF_ERROR(p);
216
217 if (stdout_out != NULL) {
218 *stdout_out = stdout_pipe;
219 } else {
220 close(stdout_pipe);
221 }
222 if (stderr_out != NULL) {
223 *stderr_out = stderr_pipe;
224 } else {
225 close(stderr_pipe);
226 }
227 return p;
228 }
229
230
231 // Drain fd into a buffer pointed to by 'buffer'. Assumes that the data is a
232 // C string, and null-terminates it. Returns the number of bytes read.
233 static intptr_t drain_fd(int fd, char** buffer) {
234 const intptr_t kDrainInitSize = 64;
235 char* buf = reinterpret_cast<char*>(malloc(kDrainInitSize));
236 intptr_t free_space = kDrainInitSize;
237 intptr_t total_read = 0;
238 intptr_t read_size = 0;
239 while ((read_size = read(fd, buf + total_read, free_space)) != 0) {
240 if (read_size == -1) {
241 break;
242 }
243 total_read += read_size;
244 free_space -= read_size;
245 if (free_space <= 1) {
246 // new_size = size * 1.5.
247 intptr_t new_size = (total_read << 1) - (total_read >> 1);
248 buf = reinterpret_cast<char*>(realloc(buf, new_size));
249 free_space = new_size - total_read;
250 }
251 }
252 buf[total_read] = '\0';
253 close(fd);
254 *buffer = buf;
255 return total_read;
256 }
257
258
259 // Runs test 'test_name' and gives stdout and stderr for the test in
260 // 'test_stdout' and 'test_stderr'. Returns the exit code from the test.
261 static int run_test(mx_handle_t binary_vmo, const char* test_name,
262 char** test_stdout, char** test_stderr) {
263 int stdout_pipe = -1;
264 int stderr_pipe = -1;
265 mx_handle_t p = start_test(binary_vmo, test_name, &stdout_pipe, &stderr_pipe);
266 RETURN_IF_ERROR(p);
267
268 drain_fd(stdout_pipe, test_stdout);
269 drain_fd(stderr_pipe, test_stderr);
163 270
164 mx_signals_state_t state; 271 mx_signals_state_t state;
165 mx_status_t r = mx_handle_wait_one( 272 mx_status_t r = mx_handle_wait_one(
166 p, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, &state); 273 p, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, &state);
167 if (r != NO_ERROR) { 274 RETURN_IF_ERROR(r);
168 fprintf(stderr, "[process(%x): wait failed? %d]\n", p, r);
169 return -1;
170 }
171 275
172 mx_process_info_t proc_info; 276 mx_process_info_t proc_info;
173 mx_ssize_t ret = mx_handle_get_info( 277 mx_ssize_t info_size = mx_handle_get_info(
174 p, MX_INFO_PROCESS, &proc_info, sizeof(proc_info)); 278 p, MX_INFO_PROCESS, &proc_info, sizeof(proc_info));
175 if (ret != sizeof(proc_info)) { 279 RETURN_IF_ERROR(info_size);
176 fprintf(stderr, "[process(%x): handle_get_info failed? %ld]\n", p, ret);
177 return -1;
178 }
179 280
180 mx_handle_close(p); 281 r = mx_handle_close(p);
282 RETURN_IF_ERROR(r);
181 return proc_info.return_code; 283 return proc_info.return_code;
182 } 284 }
183 285
184 286
185 static void handle_result(intptr_t result, const char* test) { 287 static void handle_result(
288 intptr_t result, char* test_stdout, char* test_stderr, const char* test) {
186 if (result != 0) { 289 if (result != 0) {
187 if (!isExpectFail(test) && !isBug(test)) { 290 if (!isExpectFail(test) && !isBug(test)) {
188 printf("******** Test %s FAILED\n", test); 291 printf("**** Test %s FAILED\n\nstdout:\n%s\nstderr:\n%s\n",
292 test, test_stdout, test_stderr);
293 } else {
294 printf("Test %s FAILED and is expected to fail\n", test);
189 } 295 }
190 } else { 296 } else {
191 if (isExpectFail(test)) { 297 if (isExpectFail(test)) {
192 printf("******** Test %s is expected to fail, but PASSED\n", test); 298 printf("**** Test %s is expected to fail, but PASSED\n\n"
193 } 299 "stdout:\n%s\nstderr:\n%s\n",
194 if (isBug(test)) { 300 test, test_stdout, test_stderr);
195 printf("******** Test %s is marked as a bug, but PASSED\n", test); 301 } else if (isBug(test)) {
302 printf("**** Test %s is marked as a bug, but PASSED\n", test);
303 } else {
304 printf("Test %s PASSED\n", test);
196 } 305 }
197 } 306 }
198 } 307 }
199 308
200 309
201 typedef struct { 310 typedef struct {
202 pthread_mutex_t* test_list_lock; 311 pthread_mutex_t* test_list_lock;
203 char** test_list; 312 char** test_list;
204 intptr_t test_list_length; 313 intptr_t test_list_length;
205 intptr_t* test_list_index; 314 intptr_t* test_list_index;
315 mx_handle_t binary_vmo;
206 } runner_args_t; 316 } runner_args_t;
207 317
208 318
209 static void* test_runner_thread(void* arg) { 319 static void* test_runner_thread(void* arg) {
210 runner_args_t* args = reinterpret_cast<runner_args_t*>(arg); 320 runner_args_t* args = reinterpret_cast<runner_args_t*>(arg);
211 321
212 pthread_mutex_lock(args->test_list_lock); 322 pthread_mutex_lock(args->test_list_lock);
323 mx_handle_t binary_vmo = args->binary_vmo;
213 while (*args->test_list_index < args->test_list_length) { 324 while (*args->test_list_index < args->test_list_length) {
214 const intptr_t index = *args->test_list_index; 325 const intptr_t index = *args->test_list_index;
215 *args->test_list_index = index + 1; 326 *args->test_list_index = index + 1;
216 pthread_mutex_unlock(args->test_list_lock); 327 pthread_mutex_unlock(args->test_list_lock);
328
217 const char* test = args->test_list[index]; 329 const char* test = args->test_list[index];
218 handle_result(run_test(test), test); 330 char* test_stdout = NULL;
331 char* test_stderr = NULL;
332 mx_handle_t vmo_dup = mx_handle_duplicate(binary_vmo, MX_RIGHT_SAME_RIGHTS);
333 int test_status = run_test(vmo_dup, test, &test_stdout, &test_stderr);
334 handle_result(test_status, test_stdout, test_stderr, test);
335 free(test_stdout);
336 free(test_stderr);
219 pthread_mutex_lock(args->test_list_lock); 337 pthread_mutex_lock(args->test_list_lock);
220 } 338 }
221 pthread_mutex_unlock(args->test_list_lock); 339 pthread_mutex_unlock(args->test_list_lock);
222 340
223 return NULL; 341 return NULL;
224 } 342 }
225 343
226 344
227 static void trim(char* line) { 345 static void run_all_tests(runner_args_t* args) {
228 const intptr_t line_len = strlen(line); 346 const intptr_t num_cpus = sysconf(_SC_NPROCESSORS_CONF);
229 if (line[line_len - 1] == '\n') { 347 pthread_t* threads =
230 line[line_len - 1] = '\0'; 348 reinterpret_cast<pthread_t*>(malloc(num_cpus * sizeof(pthread_t)));
349 for (int i = 0; i < num_cpus; i++) {
350 pthread_create(&threads[i], NULL, test_runner_thread, args);
231 } 351 }
352 for (int i = 0; i < num_cpus; i++) {
353 pthread_join(threads[i], NULL);
354 }
355 free(threads);
232 } 356 }
233 357
234 358
235 static bool should_run(const char* test) { 359 static bool should_run(const char* test) {
236 return !(test[0] == '#') && !isSkip(test); 360 return !(test[0] == '#') && !isSkip(test);
237 } 361 }
238 362
239 363
240 static intptr_t count_lines(FILE* fp) { 364 static char** parse_test_list(char* list_output, intptr_t* length) {
241 intptr_t lines = 0; 365 const intptr_t list_output_length = strlen(list_output);
242 366 intptr_t test_count = 0;
243 // Make sure we're at the beginning of the file. 367 for (int i = 0; i < list_output_length; i++) {
244 rewind(fp); 368 if (list_output[i] == '\n') {
245 369 test_count++;
246 intptr_t ch;
247 while ((ch = fgetc(fp)) != EOF) {
248 if (ch == '\n') {
249 lines++;
250 } 370 }
251 } 371 }
252 372 char** test_list;
253 rewind(fp); 373 test_list = reinterpret_cast<char**>(malloc(test_count * sizeof(*test_list)));
254 return lines; 374 char* test = list_output;
255 } 375 char* strtok_context;
256 376 intptr_t idx = 0;
257 377 while ((test = strtok_r(test, "\n", &strtok_context)) != NULL) {
258 static intptr_t read_lines(FILE* fp, char** lines, intptr_t lines_length) { 378 if (should_run(test)) {
259 char* test = NULL; 379 test_list[idx] = strdup(test);
260 size_t len = 0; 380 idx++;
261 ssize_t read;
262 intptr_t i = 0;
263 while (((read = getline(&test, &len, fp)) != -1) && (i < lines_length)) {
264 trim(test);
265 if (!should_run(test)) {
266 continue;
267 } 381 }
268 lines[i] = strdup(test); 382 test = NULL;
269 i++;
270 } 383 }
271 384
272 if (test != NULL) { 385 *length = idx;
273 free(test); 386 return test_list;
274 }
275 return i;
276 } 387 }
277 388
278 389
279 int main(int argc, char** argv) { 390 int main(int argc, char** argv) {
280 if (argc <= 1) { 391 // TODO(zra): Read test binary path from the command line.
281 fprintf(stderr, "Pass the path to a file containing the list of tests\n");
282 return -1;
283 }
284 const char* tests_path = argv[1];
285 392
286 FILE* fp = fopen(tests_path, "r"); 393 // Load in the binary.
287 if (fp == NULL) { 394 mx_handle_t binary_vmo = launchpad_vmo_from_file(kRunVmTestsPath);
288 fprintf(stderr, "Failed to read the file: %s\n", tests_path); 395 RETURN_IF_ERROR(binary_vmo);
289 return -1; 396
397 // Run with --list to grab the list of tests.
398 char* list_stdout = NULL;
399 char* list_stderr = NULL;
400 mx_handle_t list_vmo = mx_handle_duplicate(binary_vmo, MX_RIGHT_SAME_RIGHTS);
401 RETURN_IF_ERROR(list_vmo);
402 int list_result = run_test(list_vmo, "--list", &list_stdout, &list_stderr);
403 if (list_result != 0) {
404 fprintf(stderr, "Failed to list tests: %s\n%s\n", list_stdout, list_stderr);
405 fflush(0);
406 free(list_stdout);
407 free(list_stderr);
408 return list_result;
290 } 409 }
291 410
292 intptr_t lines_count = count_lines(fp); 411 // Parse the test list into an array of C strings.
293 char** test_list = 412 intptr_t lines_count;
294 reinterpret_cast<char**>(malloc(sizeof(*test_list) * lines_count)); 413 char** test_list = parse_test_list(list_stdout, &lines_count);
295 lines_count = read_lines(fp, test_list, lines_count); 414 free(list_stdout);
296 fclose(fp); 415 free(list_stderr);
297 416
417 fprintf(stdout, "Found %ld tests\n", lines_count);
418 fflush(0);
419
420 // Run the tests across a number of threads equal to the number of cores.
298 pthread_mutex_t args_mutex; 421 pthread_mutex_t args_mutex;
299 pthread_mutex_init(&args_mutex, NULL); 422 pthread_mutex_init(&args_mutex, NULL);
300 intptr_t test_list_index = 0; 423 intptr_t test_list_index = 0;
301 runner_args_t args; 424 runner_args_t args;
302 args.test_list_lock = &args_mutex; 425 args.test_list_lock = &args_mutex;
303 args.test_list = test_list; 426 args.test_list = test_list;
304 args.test_list_length = lines_count; 427 args.test_list_length = lines_count;
305 args.test_list_index = &test_list_index; 428 args.test_list_index = &test_list_index;
429 args.binary_vmo = binary_vmo;
430 run_all_tests(&args);
306 431
307 const intptr_t num_cpus = sysconf(_SC_NPROCESSORS_CONF); 432 // Cleanup.
308 pthread_t* threads =
309 reinterpret_cast<pthread_t*>(malloc(num_cpus * sizeof(pthread_t)));
310 for (int i = 0; i < num_cpus; i++) {
311 pthread_create(&threads[i], NULL, test_runner_thread, &args);
312 }
313
314 for (int i = 0; i < num_cpus; i++) {
315 pthread_join(threads[i], NULL);
316 }
317
318 free(threads);
319 for (int i = 0; i < lines_count; i++) { 433 for (int i = 0; i < lines_count; i++) {
320 free(test_list[i]); 434 free(test_list[i]);
321 } 435 }
322 free(test_list); 436 free(test_list);
323 pthread_mutex_destroy(&args_mutex); 437 pthread_mutex_destroy(&args_mutex);
438 mx_status_t status = mx_handle_close(binary_vmo);
439 RETURN_IF_ERROR(status);
324 440
441 // Complain if we didn't try to run all of the tests.
325 if (test_list_index != lines_count) { 442 if (test_list_index != lines_count) {
326 fprintf(stderr, "Failed to attempt all the tests!\n"); 443 fprintf(stderr, "Failed to attempt all the tests!\n");
444 fflush(0);
327 return -1; 445 return -1;
328 } 446 }
329
330 return 0; 447 return 0;
331 } 448 }
OLDNEW
« no previous file with comments | « runtime/bin/BUILD.gn ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698