1/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to 5 * deal in the Software without restriction, including without limitation the 6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 * sell copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 * IN THE SOFTWARE. 20 */ 21 22/* This benchmark spawns itself 1000 times. */ 23 24#include "task.h" 25#include "uv.h" 26 27static uv_loop_t* loop; 28 29static int N = 1000; 30static int done; 31 32static uv_process_t process; 33static uv_process_options_t options; 34static char exepath[1024]; 35static size_t exepath_size = 1024; 36static char* args[3]; 37static uv_pipe_t out; 38 39#define OUTPUT_SIZE 1024 40static char output[OUTPUT_SIZE]; 41static int output_used; 42 43static int process_open; 44static int pipe_open; 45 46 47static void spawn(void); 48 49 50static void maybe_spawn(void) { 51 if (process_open == 0 && pipe_open == 0) { 52 done++; 53 if (done < N) { 54 spawn(); 55 } 56 } 57} 58 59 60static void process_close_cb(uv_handle_t* handle) { 61 ASSERT_EQ(1, process_open); 62 process_open = 0; 63 maybe_spawn(); 64} 65 66 67static void exit_cb(uv_process_t* process, 68 int64_t exit_status, 69 int term_signal) { 70 ASSERT_EQ(42, exit_status); 71 ASSERT_OK(term_signal); 72 uv_close((uv_handle_t*)process, process_close_cb); 73} 74 75 76static void on_alloc(uv_handle_t* handle, 77 size_t suggested_size, 78 uv_buf_t* buf) { 79 buf->base = output + output_used; 80 buf->len = OUTPUT_SIZE - output_used; 81} 82 83 84static void pipe_close_cb(uv_handle_t* pipe) { 85 ASSERT_EQ(1, pipe_open); 86 pipe_open = 0; 87 maybe_spawn(); 88} 89 90 91static void on_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* buf) { 92 if (nread > 0) { 93 ASSERT_EQ(1, pipe_open); 94 output_used += nread; 95 } else if (nread < 0) { 96 if (nread == UV_EOF) { 97 uv_close((uv_handle_t*)pipe, pipe_close_cb); 98 } 99 } 100} 101 102 103static void spawn(void) { 104 uv_stdio_container_t stdio[2]; 105 int r; 106 107 ASSERT_OK(process_open); 108 ASSERT_OK(pipe_open); 109 110 args[0] = exepath; 111 args[1] = "spawn_helper"; 112 args[2] = NULL; 113 options.file = exepath; 114 options.args = args; 115 options.exit_cb = exit_cb; 116 117 uv_pipe_init(loop, &out, 0); 118 119 options.stdio = stdio; 120 options.stdio_count = 2; 121 options.stdio[0].flags = UV_IGNORE; 122 options.stdio[1].flags = UV_CREATE_PIPE | UV_WRITABLE_PIPE; 123 options.stdio[1].data.stream = (uv_stream_t*)&out; 124 125 r = uv_spawn(loop, &process, &options); 126 ASSERT_OK(r); 127 128 process_open = 1; 129 pipe_open = 1; 130 output_used = 0; 131 132 r = uv_read_start((uv_stream_t*) &out, on_alloc, on_read); 133 ASSERT_OK(r); 134} 135 136 137BENCHMARK_IMPL(spawn) { 138 int r; 139 static int64_t start_time, end_time; 140 141 loop = uv_default_loop(); 142 143 r = uv_exepath(exepath, &exepath_size); 144 ASSERT_OK(r); 145 exepath[exepath_size] = '\0'; 146 147 uv_update_time(loop); 148 start_time = uv_now(loop); 149 150 spawn(); 151 152 r = uv_run(loop, UV_RUN_DEFAULT); 153 ASSERT_OK(r); 154 155 uv_update_time(loop); 156 end_time = uv_now(loop); 157 158 fprintf(stderr, "spawn: %.0f spawns/s\n", 159 (double) N / (double) (end_time - start_time) * 1000.0); 160 fflush(stderr); 161 162 MAKE_VALGRIND_HAPPY(loop); 163 return 0; 164} 165