|
160
|
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_EQ(1, process_open);
|
|
|
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_EQ(42, exit_status);
|
|
|
71 ASSERT_OK(term_signal);
|
|
|
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_EQ(1, pipe_open);
|
|
|
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_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
|
|
|
103 static 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
|
|
|
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_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 }
|