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

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

Powered by Google App Engine
This is Rietveld 408576698