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 27 static uv_loop_t* loop; 28 29 static int N = 1000; 30 static int done; 31 32 static uv_process_t process; 33 static uv_process_options_t options; 34 static char exepath[1024]; 35 static size_t exepath_size = 1024; 36 static char* args[3]; 37 static uv_pipe_t out; 38 39 #define OUTPUT_SIZE 1024 40 static char output[OUTPUT_SIZE]; 41 static int output_used; 42 43 static int process_open; 44 static int pipe_open; 45 46 47 static void spawn(void); 48 49 50 static 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 60 static void process_close_cb(uv_handle_t* handle) { 61 ASSERT(process_open == 1); 62 process_open = 0; 63 maybe_spawn(); 64 } 65 66 67 static void exit_cb(uv_process_t* process, 68 int64_t exit_status, 69 int term_signal) { 70 ASSERT(exit_status == 42); 71 ASSERT(term_signal == 0); 72 uv_close((uv_handle_t*)process, process_close_cb); 73 } 74 75 76 static 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 84 static void pipe_close_cb(uv_handle_t* pipe) { 85 ASSERT(pipe_open == 1); 86 pipe_open = 0; 87 maybe_spawn(); 88 } 89 90 91 static void on_read(uv_stream_t* pipe, ssize_t nread, const uv_buf_t* buf) { 92 if (nread > 0) { 93 ASSERT(pipe_open == 1); 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 103 static void spawn(void) { 104 uv_stdio_container_t stdio[2]; 105 int r; 106 107 ASSERT(process_open == 0); 108 ASSERT(pipe_open == 0); 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(r == 0); 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(r == 0); 134 } 135 136 137 BENCHMARK_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(r == 0); 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(r == 0); 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(); 163 return 0; 164 } 165