forked from denoland/deno
-
Notifications
You must be signed in to change notification settings - Fork 0
/
http_bench.js
143 lines (124 loc) · 3.32 KB
/
http_bench.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// This is not a real HTTP server. We read blindly one time into 'requestBuf',
// then write this fixed 'responseBuf'. The point of this benchmark is to
// exercise the event loop in a simple yet semi-realistic way.
const OP_LISTEN = 1;
const OP_ACCEPT = 2;
const OP_READ = 3;
const OP_WRITE = 4;
const OP_CLOSE = 5;
const requestBuf = new Uint8Array(64 * 1024);
const responseBuf = new Uint8Array(
"HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\nHello World\n"
.split("")
.map(c => c.charCodeAt(0))
);
const promiseMap = new Map();
let nextPromiseId = 1;
function assert(cond) {
if (!cond) {
throw Error("assert");
}
}
function createResolvable() {
let methods;
const promise = new Promise((resolve, reject) => {
methods = { resolve, reject };
});
return Object.assign(promise, methods);
}
const scratch32 = new Int32Array(4);
const scratchBytes = new Uint8Array(
scratch32.buffer,
scratch32.byteOffset,
scratch32.byteLength
);
assert(scratchBytes.byteLength === 4 * 4);
function send(promiseId, opId, arg, zeroCopy = null) {
scratch32[0] = promiseId;
scratch32[1] = opId;
scratch32[2] = arg;
scratch32[3] = -1;
return Deno.core.dispatch(scratchBytes, zeroCopy);
}
/** Returns Promise<number> */
function sendAsync(opId, arg, zeroCopy = null) {
const promiseId = nextPromiseId++;
const p = createResolvable();
promiseMap.set(promiseId, p);
send(promiseId, opId, arg, zeroCopy);
return p;
}
function recordFromBuf(buf) {
assert(buf.byteLength === 16);
const buf32 = new Int32Array(buf.buffer, buf.byteOffset, buf.byteLength / 4);
return {
promiseId: buf32[0],
opId: buf32[1],
arg: buf32[2],
result: buf32[3]
};
}
/** Returns i32 number */
function sendSync(opId, arg) {
const buf = send(0, opId, arg);
const record = recordFromBuf(buf);
return record.result;
}
function handleAsyncMsgFromRust(buf) {
const record = recordFromBuf(buf);
const { promiseId, result } = record;
const p = promiseMap.get(promiseId);
promiseMap.delete(promiseId);
p.resolve(result);
}
/** Listens on 0.0.0.0:4500, returns rid. */
function listen() {
return sendSync(OP_LISTEN, -1);
}
/** Accepts a connection, returns rid. */
async function accept(rid) {
return await sendAsync(OP_ACCEPT, rid);
}
/**
* Reads a packet from the rid, presumably an http request. data is ignored.
* Returns bytes read.
*/
async function read(rid, data) {
return await sendAsync(OP_READ, rid, data);
}
/** Writes a fixed HTTP response to the socket rid. Returns bytes written. */
async function write(rid, data) {
return await sendAsync(OP_WRITE, rid, data);
}
function close(rid) {
return sendSync(OP_CLOSE, rid);
}
async function serve(rid) {
while (true) {
const nread = await read(rid, requestBuf);
if (nread <= 0) {
break;
}
const nwritten = await write(rid, responseBuf);
if (nwritten < 0) {
break;
}
}
close(rid);
}
async function main() {
Deno.core.setAsyncHandler(handleAsyncMsgFromRust);
Deno.core.print("http_bench.js start\n");
const listenerRid = listen();
Deno.core.print(`listening http:https://127.0.0.1:4544/ rid = ${listenerRid}\n`);
while (true) {
const rid = await accept(listenerRid);
// Deno.core.print(`accepted ${rid}`);
if (rid < 0) {
Deno.core.print(`accept error ${rid}`);
return;
}
serve(rid);
}
}
main();