socket-function 0.8.40 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +50 -50
- package/SocketFunction.ts +280 -276
- package/SocketFunctionTypes.ts +90 -90
- package/hot/HotReloadController.ts +105 -70
- package/mobx/UrlParam.ts +39 -39
- package/mobx/observer.tsx +49 -49
- package/mobx/promiseToObservable.tsx +41 -41
- package/package.json +30 -28
- package/require/CSSShim.ts +19 -19
- package/require/RequireController.ts +252 -252
- package/require/buffer.js +2368 -2368
- package/require/compileFlags.ts +44 -44
- package/require/require.html +13 -13
- package/require/require.js +462 -454
- package/spec.txt +115 -115
- package/src/CallFactory.ts +389 -383
- package/src/JSONLACKS/JSONLACKS.generated.js +17 -17
- package/src/JSONLACKS/JSONLACKS.pegjs +247 -247
- package/src/JSONLACKS/JSONLACKS.ts +429 -375
- package/src/args.ts +21 -21
- package/src/batching.ts +170 -126
- package/src/caching.ts +318 -314
- package/src/callHTTPHandler.ts +203 -203
- package/src/callManager.ts +134 -134
- package/src/certStore.ts +29 -25
- package/src/fixLargeNetworkCalls.ts +8 -8
- package/src/formatting/colors.ts +78 -78
- package/src/formatting/format.ts +160 -156
- package/src/formatting/logColors.ts +17 -17
- package/src/misc.ts +302 -150
- package/src/nodeCache.ts +92 -92
- package/src/nodeProxy.ts +54 -54
- package/src/profiling/getOwnTime.ts +142 -142
- package/src/profiling/measure.ts +273 -244
- package/src/profiling/stats.ts +212 -212
- package/src/profiling/tcpLagProxy.ts +63 -63
- package/src/storagePath.ts +10 -10
- package/src/tlsParsing.ts +96 -96
- package/src/types.ts +8 -8
- package/src/webSocketServer.ts +250 -237
- package/test/client.css +2 -2
- package/test/client.ts +46 -46
- package/test/server.ts +43 -43
- package/test/shared.ts +52 -58
- package/tsconfig.json +26 -26
package/src/profiling/stats.ts
CHANGED
|
@@ -1,213 +1,213 @@
|
|
|
1
|
-
export interface StatsValue {
|
|
2
|
-
count: number;
|
|
3
|
-
sum: number;
|
|
4
|
-
sumSquares: number;
|
|
5
|
-
|
|
6
|
-
// All logs use base 10
|
|
7
|
-
// This supports values from 0.1ns to 1 week
|
|
8
|
-
logn7Value: number; logn7Count: number; logn6Value: number; logn6Count: number; logn5Value: number; logn5Count: number; logn4Value: number; logn4Count: number; logn3Value: number; logn3Count: number; logn2Value: number; logn2Count: number; logn1Value: number; logn1Count: number; log0Value: number; log0VCount: number; log1Value: number; log1VCount: number; log2Value: number; log2VCount: number; log3Value: number; log3VCount: number; log4Value: number; log4VCount: number; log5Value: number; log5VCount: number; log6Value: number; log6VCount: number; log7Value: number; log7VCount: number; log8Value: number; log8VCount: number; log9Value: number; log9VCount: number;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function createStatsValue(): StatsValue {
|
|
12
|
-
return {
|
|
13
|
-
count: 0,
|
|
14
|
-
sum: 0,
|
|
15
|
-
sumSquares: 0,
|
|
16
|
-
logn7Value: 0, logn7Count: 0, logn6Value: 0, logn6Count: 0, logn5Value: 0, logn5Count: 0, logn4Value: 0, logn4Count: 0, logn3Value: 0, logn3Count: 0, logn2Value: 0, logn2Count: 0, logn1Value: 0, logn1Count: 0, log0Value: 0, log0VCount: 0, log1Value: 0, log1VCount: 0, log2Value: 0, log2VCount: 0, log3Value: 0, log3VCount: 0, log4Value: 0, log4VCount: 0, log5Value: 0, log5VCount: 0, log6Value: 0, log6VCount: 0, log7Value: 0, log7VCount: 0, log8Value: 0, log8VCount: 0, log9Value: 0, log9VCount: 0,
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// TIMING: Between 5.6ns and 8ns, depending on the size of the value (smaller values are faster to add)
|
|
21
|
-
// - A C++ implementation takes about 3.5ns, so... this is pretty fast!
|
|
22
|
-
export function addToStatsValue(stats: StatsValue, value: number) {
|
|
23
|
-
stats.count++;
|
|
24
|
-
stats.sum += value;
|
|
25
|
-
stats.sumSquares += value * value;
|
|
26
|
-
if (value < 0.000001) {
|
|
27
|
-
stats.logn7Value += value;
|
|
28
|
-
stats.logn7Count++;
|
|
29
|
-
} else if (value < 0.00001) {
|
|
30
|
-
stats.logn6Value += value;
|
|
31
|
-
stats.logn6Count++;
|
|
32
|
-
} else if (value < 0.0001) {
|
|
33
|
-
stats.logn5Value += value;
|
|
34
|
-
stats.logn5Count++;
|
|
35
|
-
} else if (value < 0.001) {
|
|
36
|
-
stats.logn4Value += value;
|
|
37
|
-
stats.logn4Count++;
|
|
38
|
-
} else if (value < 0.01) {
|
|
39
|
-
stats.logn3Value += value;
|
|
40
|
-
stats.logn3Count++;
|
|
41
|
-
} else if (value < 0.1) {
|
|
42
|
-
stats.logn2Value += value;
|
|
43
|
-
stats.logn2Count++;
|
|
44
|
-
} else if (value < 1) {
|
|
45
|
-
stats.logn1Value += value;
|
|
46
|
-
stats.logn1Count++;
|
|
47
|
-
} else if (value < 10) {
|
|
48
|
-
stats.log0Value += value;
|
|
49
|
-
stats.log0VCount++;
|
|
50
|
-
} else if (value < 100) {
|
|
51
|
-
stats.log1Value += value;
|
|
52
|
-
stats.log1VCount++;
|
|
53
|
-
} else if (value < 1000) {
|
|
54
|
-
stats.log2Value += value;
|
|
55
|
-
stats.log2VCount++;
|
|
56
|
-
} else if (value < 10000) {
|
|
57
|
-
stats.log3Value += value;
|
|
58
|
-
stats.log3VCount++;
|
|
59
|
-
} else if (value < 100000) {
|
|
60
|
-
stats.log4Value += value;
|
|
61
|
-
stats.log4VCount++;
|
|
62
|
-
} else if (value < 1000000) {
|
|
63
|
-
stats.log5Value += value;
|
|
64
|
-
stats.log5VCount++;
|
|
65
|
-
} else if (value < 10000000) {
|
|
66
|
-
stats.log6Value += value;
|
|
67
|
-
stats.log6VCount++;
|
|
68
|
-
} else if (value < 100000000) {
|
|
69
|
-
stats.log7Value += value;
|
|
70
|
-
stats.log7VCount++;
|
|
71
|
-
} else if (value < 1000000000) {
|
|
72
|
-
stats.log8Value += value;
|
|
73
|
-
stats.log8VCount++;
|
|
74
|
-
} else {
|
|
75
|
-
stats.log9Value += value;
|
|
76
|
-
stats.log9VCount++;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export function addToStats(stats: StatsValue, other: StatsValue) {
|
|
81
|
-
stats.count += other.count;
|
|
82
|
-
stats.sum += other.sum;
|
|
83
|
-
stats.sumSquares += other.sumSquares;
|
|
84
|
-
stats.logn7Value += other.logn7Value;
|
|
85
|
-
stats.logn7Count += other.logn7Count;
|
|
86
|
-
stats.logn6Value += other.logn6Value;
|
|
87
|
-
stats.logn6Count += other.logn6Count;
|
|
88
|
-
stats.logn5Value += other.logn5Value;
|
|
89
|
-
stats.logn5Count += other.logn5Count;
|
|
90
|
-
stats.logn4Value += other.logn4Value;
|
|
91
|
-
stats.logn4Count += other.logn4Count;
|
|
92
|
-
stats.logn3Value += other.logn3Value;
|
|
93
|
-
stats.logn3Count += other.logn3Count;
|
|
94
|
-
stats.logn2Value += other.logn2Value;
|
|
95
|
-
stats.logn2Count += other.logn2Count;
|
|
96
|
-
stats.logn1Value += other.logn1Value;
|
|
97
|
-
stats.logn1Count += other.logn1Count;
|
|
98
|
-
stats.log0Value += other.log0Value;
|
|
99
|
-
stats.log0VCount += other.log0VCount;
|
|
100
|
-
stats.log1Value += other.log1Value;
|
|
101
|
-
stats.log1VCount += other.log1VCount;
|
|
102
|
-
stats.log2Value += other.log2Value;
|
|
103
|
-
stats.log2VCount += other.log2VCount;
|
|
104
|
-
stats.log3Value += other.log3Value;
|
|
105
|
-
stats.log3VCount += other.log3VCount;
|
|
106
|
-
stats.log4Value += other.log4Value;
|
|
107
|
-
stats.log4VCount += other.log4VCount;
|
|
108
|
-
stats.log5Value += other.log5Value;
|
|
109
|
-
stats.log5VCount += other.log5VCount;
|
|
110
|
-
stats.log6Value += other.log6Value;
|
|
111
|
-
stats.log6VCount += other.log6VCount;
|
|
112
|
-
stats.log7Value += other.log7Value;
|
|
113
|
-
stats.log7VCount += other.log7VCount;
|
|
114
|
-
stats.log8Value += other.log8Value;
|
|
115
|
-
stats.log8VCount += other.log8VCount;
|
|
116
|
-
stats.log9Value += other.log9Value;
|
|
117
|
-
stats.log9VCount += other.log9VCount;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
interface StatsBucket {
|
|
121
|
-
sum: number;
|
|
122
|
-
count: number;
|
|
123
|
-
}
|
|
124
|
-
// Ordered from lowest average to highest average
|
|
125
|
-
function getStatsBuckets(stats: StatsValue): StatsBucket[] {
|
|
126
|
-
return [
|
|
127
|
-
{ sum: stats.logn7Value, count: stats.logn7Count },
|
|
128
|
-
{ sum: stats.logn6Value, count: stats.logn6Count },
|
|
129
|
-
{ sum: stats.logn5Value, count: stats.logn5Count },
|
|
130
|
-
{ sum: stats.logn4Value, count: stats.logn4Count },
|
|
131
|
-
{ sum: stats.logn3Value, count: stats.logn3Count },
|
|
132
|
-
{ sum: stats.logn2Value, count: stats.logn2Count },
|
|
133
|
-
{ sum: stats.logn1Value, count: stats.logn1Count },
|
|
134
|
-
{ sum: stats.log0Value, count: stats.log0VCount },
|
|
135
|
-
{ sum: stats.log1Value, count: stats.log1VCount },
|
|
136
|
-
{ sum: stats.log2Value, count: stats.log2VCount },
|
|
137
|
-
{ sum: stats.log3Value, count: stats.log3VCount },
|
|
138
|
-
{ sum: stats.log4Value, count: stats.log4VCount },
|
|
139
|
-
{ sum: stats.log5Value, count: stats.log5VCount },
|
|
140
|
-
{ sum: stats.log6Value, count: stats.log6VCount },
|
|
141
|
-
{ sum: stats.log7Value, count: stats.log7VCount },
|
|
142
|
-
{ sum: stats.log8Value, count: stats.log8VCount },
|
|
143
|
-
{ sum: stats.log9Value, count: stats.log9VCount },
|
|
144
|
-
];
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export interface StatsTop {
|
|
148
|
-
// NOTE: countFraction <= valueFraction, because we take the largest values
|
|
149
|
-
countFraction: number;
|
|
150
|
-
valueFraction: number;
|
|
151
|
-
count: number;
|
|
152
|
-
value: number;
|
|
153
|
-
topHeavy: boolean;
|
|
154
|
-
}
|
|
155
|
-
/** Identifies cases where the value is concentrated in few instances. This indicates most of the value (time)
|
|
156
|
-
* is not spent on the common case, but on an outlier. Which isn't a problem, it just means that the measurements
|
|
157
|
-
* should be more precise, to pull that heavy case out.
|
|
158
|
-
*/
|
|
159
|
-
export function getStatsTop(stats: StatsValue): StatsTop {
|
|
160
|
-
if (stats.sum === 0) {
|
|
161
|
-
return { countFraction: 1, valueFraction: 1, count: 0, value: 0, topHeavy: false, };
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const minFraction = 0.2;
|
|
165
|
-
|
|
166
|
-
let totalSum = stats.sum;
|
|
167
|
-
let totalCount = stats.count;
|
|
168
|
-
let totalMean = totalSum / totalCount;
|
|
169
|
-
|
|
170
|
-
// Find the sum above the average (with a minimum of minFraction, as sometimes there isn't really anything above the average)
|
|
171
|
-
let buckets = getStatsBuckets(stats);
|
|
172
|
-
buckets.reverse();
|
|
173
|
-
|
|
174
|
-
let curSum = 0;
|
|
175
|
-
let curCount = 0;
|
|
176
|
-
for (let entry of buckets) {
|
|
177
|
-
let mean = entry.sum / entry.count;
|
|
178
|
-
if (curSum > totalSum * minFraction && mean < totalMean) break;
|
|
179
|
-
|
|
180
|
-
curSum += entry.sum;
|
|
181
|
-
curCount += entry.count;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
let countFraction = curCount / totalCount;
|
|
185
|
-
let valueFraction = curSum / totalSum;
|
|
186
|
-
|
|
187
|
-
return {
|
|
188
|
-
countFraction,
|
|
189
|
-
valueFraction,
|
|
190
|
-
count: curCount,
|
|
191
|
-
value: curSum,
|
|
192
|
-
// If more than 50% is above the average, it's top heavy
|
|
193
|
-
topHeavy: valueFraction / countFraction > 2 && valueFraction > 0.4,
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
function benchmarkAddToStats() {
|
|
202
|
-
let stats = createStatsValue();
|
|
203
|
-
let start = Date.now();
|
|
204
|
-
const count = 1000000;
|
|
205
|
-
for (let i = 0; i < count; i++) {
|
|
206
|
-
addToStatsValue(stats, 10000000000);
|
|
207
|
-
}
|
|
208
|
-
let end = Date.now();
|
|
209
|
-
let time = end - start;
|
|
210
|
-
let timePer = (time) / count * 1000 * 1000;
|
|
211
|
-
console.log(`Time per: ${timePer}ns, in ${time}ms`);
|
|
212
|
-
}
|
|
1
|
+
export interface StatsValue {
|
|
2
|
+
count: number;
|
|
3
|
+
sum: number;
|
|
4
|
+
sumSquares: number;
|
|
5
|
+
|
|
6
|
+
// All logs use base 10
|
|
7
|
+
// This supports values from 0.1ns to 1 week
|
|
8
|
+
logn7Value: number; logn7Count: number; logn6Value: number; logn6Count: number; logn5Value: number; logn5Count: number; logn4Value: number; logn4Count: number; logn3Value: number; logn3Count: number; logn2Value: number; logn2Count: number; logn1Value: number; logn1Count: number; log0Value: number; log0VCount: number; log1Value: number; log1VCount: number; log2Value: number; log2VCount: number; log3Value: number; log3VCount: number; log4Value: number; log4VCount: number; log5Value: number; log5VCount: number; log6Value: number; log6VCount: number; log7Value: number; log7VCount: number; log8Value: number; log8VCount: number; log9Value: number; log9VCount: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function createStatsValue(): StatsValue {
|
|
12
|
+
return {
|
|
13
|
+
count: 0,
|
|
14
|
+
sum: 0,
|
|
15
|
+
sumSquares: 0,
|
|
16
|
+
logn7Value: 0, logn7Count: 0, logn6Value: 0, logn6Count: 0, logn5Value: 0, logn5Count: 0, logn4Value: 0, logn4Count: 0, logn3Value: 0, logn3Count: 0, logn2Value: 0, logn2Count: 0, logn1Value: 0, logn1Count: 0, log0Value: 0, log0VCount: 0, log1Value: 0, log1VCount: 0, log2Value: 0, log2VCount: 0, log3Value: 0, log3VCount: 0, log4Value: 0, log4VCount: 0, log5Value: 0, log5VCount: 0, log6Value: 0, log6VCount: 0, log7Value: 0, log7VCount: 0, log8Value: 0, log8VCount: 0, log9Value: 0, log9VCount: 0,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// TIMING: Between 5.6ns and 8ns, depending on the size of the value (smaller values are faster to add)
|
|
21
|
+
// - A C++ implementation takes about 3.5ns, so... this is pretty fast!
|
|
22
|
+
export function addToStatsValue(stats: StatsValue, value: number) {
|
|
23
|
+
stats.count++;
|
|
24
|
+
stats.sum += value;
|
|
25
|
+
stats.sumSquares += value * value;
|
|
26
|
+
if (value < 0.000001) {
|
|
27
|
+
stats.logn7Value += value;
|
|
28
|
+
stats.logn7Count++;
|
|
29
|
+
} else if (value < 0.00001) {
|
|
30
|
+
stats.logn6Value += value;
|
|
31
|
+
stats.logn6Count++;
|
|
32
|
+
} else if (value < 0.0001) {
|
|
33
|
+
stats.logn5Value += value;
|
|
34
|
+
stats.logn5Count++;
|
|
35
|
+
} else if (value < 0.001) {
|
|
36
|
+
stats.logn4Value += value;
|
|
37
|
+
stats.logn4Count++;
|
|
38
|
+
} else if (value < 0.01) {
|
|
39
|
+
stats.logn3Value += value;
|
|
40
|
+
stats.logn3Count++;
|
|
41
|
+
} else if (value < 0.1) {
|
|
42
|
+
stats.logn2Value += value;
|
|
43
|
+
stats.logn2Count++;
|
|
44
|
+
} else if (value < 1) {
|
|
45
|
+
stats.logn1Value += value;
|
|
46
|
+
stats.logn1Count++;
|
|
47
|
+
} else if (value < 10) {
|
|
48
|
+
stats.log0Value += value;
|
|
49
|
+
stats.log0VCount++;
|
|
50
|
+
} else if (value < 100) {
|
|
51
|
+
stats.log1Value += value;
|
|
52
|
+
stats.log1VCount++;
|
|
53
|
+
} else if (value < 1000) {
|
|
54
|
+
stats.log2Value += value;
|
|
55
|
+
stats.log2VCount++;
|
|
56
|
+
} else if (value < 10000) {
|
|
57
|
+
stats.log3Value += value;
|
|
58
|
+
stats.log3VCount++;
|
|
59
|
+
} else if (value < 100000) {
|
|
60
|
+
stats.log4Value += value;
|
|
61
|
+
stats.log4VCount++;
|
|
62
|
+
} else if (value < 1000000) {
|
|
63
|
+
stats.log5Value += value;
|
|
64
|
+
stats.log5VCount++;
|
|
65
|
+
} else if (value < 10000000) {
|
|
66
|
+
stats.log6Value += value;
|
|
67
|
+
stats.log6VCount++;
|
|
68
|
+
} else if (value < 100000000) {
|
|
69
|
+
stats.log7Value += value;
|
|
70
|
+
stats.log7VCount++;
|
|
71
|
+
} else if (value < 1000000000) {
|
|
72
|
+
stats.log8Value += value;
|
|
73
|
+
stats.log8VCount++;
|
|
74
|
+
} else {
|
|
75
|
+
stats.log9Value += value;
|
|
76
|
+
stats.log9VCount++;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function addToStats(stats: StatsValue, other: StatsValue) {
|
|
81
|
+
stats.count += other.count;
|
|
82
|
+
stats.sum += other.sum;
|
|
83
|
+
stats.sumSquares += other.sumSquares;
|
|
84
|
+
stats.logn7Value += other.logn7Value;
|
|
85
|
+
stats.logn7Count += other.logn7Count;
|
|
86
|
+
stats.logn6Value += other.logn6Value;
|
|
87
|
+
stats.logn6Count += other.logn6Count;
|
|
88
|
+
stats.logn5Value += other.logn5Value;
|
|
89
|
+
stats.logn5Count += other.logn5Count;
|
|
90
|
+
stats.logn4Value += other.logn4Value;
|
|
91
|
+
stats.logn4Count += other.logn4Count;
|
|
92
|
+
stats.logn3Value += other.logn3Value;
|
|
93
|
+
stats.logn3Count += other.logn3Count;
|
|
94
|
+
stats.logn2Value += other.logn2Value;
|
|
95
|
+
stats.logn2Count += other.logn2Count;
|
|
96
|
+
stats.logn1Value += other.logn1Value;
|
|
97
|
+
stats.logn1Count += other.logn1Count;
|
|
98
|
+
stats.log0Value += other.log0Value;
|
|
99
|
+
stats.log0VCount += other.log0VCount;
|
|
100
|
+
stats.log1Value += other.log1Value;
|
|
101
|
+
stats.log1VCount += other.log1VCount;
|
|
102
|
+
stats.log2Value += other.log2Value;
|
|
103
|
+
stats.log2VCount += other.log2VCount;
|
|
104
|
+
stats.log3Value += other.log3Value;
|
|
105
|
+
stats.log3VCount += other.log3VCount;
|
|
106
|
+
stats.log4Value += other.log4Value;
|
|
107
|
+
stats.log4VCount += other.log4VCount;
|
|
108
|
+
stats.log5Value += other.log5Value;
|
|
109
|
+
stats.log5VCount += other.log5VCount;
|
|
110
|
+
stats.log6Value += other.log6Value;
|
|
111
|
+
stats.log6VCount += other.log6VCount;
|
|
112
|
+
stats.log7Value += other.log7Value;
|
|
113
|
+
stats.log7VCount += other.log7VCount;
|
|
114
|
+
stats.log8Value += other.log8Value;
|
|
115
|
+
stats.log8VCount += other.log8VCount;
|
|
116
|
+
stats.log9Value += other.log9Value;
|
|
117
|
+
stats.log9VCount += other.log9VCount;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
interface StatsBucket {
|
|
121
|
+
sum: number;
|
|
122
|
+
count: number;
|
|
123
|
+
}
|
|
124
|
+
// Ordered from lowest average to highest average
|
|
125
|
+
function getStatsBuckets(stats: StatsValue): StatsBucket[] {
|
|
126
|
+
return [
|
|
127
|
+
{ sum: stats.logn7Value, count: stats.logn7Count },
|
|
128
|
+
{ sum: stats.logn6Value, count: stats.logn6Count },
|
|
129
|
+
{ sum: stats.logn5Value, count: stats.logn5Count },
|
|
130
|
+
{ sum: stats.logn4Value, count: stats.logn4Count },
|
|
131
|
+
{ sum: stats.logn3Value, count: stats.logn3Count },
|
|
132
|
+
{ sum: stats.logn2Value, count: stats.logn2Count },
|
|
133
|
+
{ sum: stats.logn1Value, count: stats.logn1Count },
|
|
134
|
+
{ sum: stats.log0Value, count: stats.log0VCount },
|
|
135
|
+
{ sum: stats.log1Value, count: stats.log1VCount },
|
|
136
|
+
{ sum: stats.log2Value, count: stats.log2VCount },
|
|
137
|
+
{ sum: stats.log3Value, count: stats.log3VCount },
|
|
138
|
+
{ sum: stats.log4Value, count: stats.log4VCount },
|
|
139
|
+
{ sum: stats.log5Value, count: stats.log5VCount },
|
|
140
|
+
{ sum: stats.log6Value, count: stats.log6VCount },
|
|
141
|
+
{ sum: stats.log7Value, count: stats.log7VCount },
|
|
142
|
+
{ sum: stats.log8Value, count: stats.log8VCount },
|
|
143
|
+
{ sum: stats.log9Value, count: stats.log9VCount },
|
|
144
|
+
];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface StatsTop {
|
|
148
|
+
// NOTE: countFraction <= valueFraction, because we take the largest values
|
|
149
|
+
countFraction: number;
|
|
150
|
+
valueFraction: number;
|
|
151
|
+
count: number;
|
|
152
|
+
value: number;
|
|
153
|
+
topHeavy: boolean;
|
|
154
|
+
}
|
|
155
|
+
/** Identifies cases where the value is concentrated in few instances. This indicates most of the value (time)
|
|
156
|
+
* is not spent on the common case, but on an outlier. Which isn't a problem, it just means that the measurements
|
|
157
|
+
* should be more precise, to pull that heavy case out.
|
|
158
|
+
*/
|
|
159
|
+
export function getStatsTop(stats: StatsValue): StatsTop {
|
|
160
|
+
if (stats.sum === 0) {
|
|
161
|
+
return { countFraction: 1, valueFraction: 1, count: 0, value: 0, topHeavy: false, };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const minFraction = 0.2;
|
|
165
|
+
|
|
166
|
+
let totalSum = stats.sum;
|
|
167
|
+
let totalCount = stats.count;
|
|
168
|
+
let totalMean = totalSum / totalCount;
|
|
169
|
+
|
|
170
|
+
// Find the sum above the average (with a minimum of minFraction, as sometimes there isn't really anything above the average)
|
|
171
|
+
let buckets = getStatsBuckets(stats);
|
|
172
|
+
buckets.reverse();
|
|
173
|
+
|
|
174
|
+
let curSum = 0;
|
|
175
|
+
let curCount = 0;
|
|
176
|
+
for (let entry of buckets) {
|
|
177
|
+
let mean = entry.sum / entry.count;
|
|
178
|
+
if (curSum > totalSum * minFraction && mean < totalMean) break;
|
|
179
|
+
|
|
180
|
+
curSum += entry.sum;
|
|
181
|
+
curCount += entry.count;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
let countFraction = curCount / totalCount;
|
|
185
|
+
let valueFraction = curSum / totalSum;
|
|
186
|
+
|
|
187
|
+
return {
|
|
188
|
+
countFraction,
|
|
189
|
+
valueFraction,
|
|
190
|
+
count: curCount,
|
|
191
|
+
value: curSum,
|
|
192
|
+
// If more than 50% is above the average, it's top heavy
|
|
193
|
+
topHeavy: valueFraction / countFraction > 2 && valueFraction > 0.4,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
function benchmarkAddToStats() {
|
|
202
|
+
let stats = createStatsValue();
|
|
203
|
+
let start = Date.now();
|
|
204
|
+
const count = 1000000;
|
|
205
|
+
for (let i = 0; i < count; i++) {
|
|
206
|
+
addToStatsValue(stats, 10000000000);
|
|
207
|
+
}
|
|
208
|
+
let end = Date.now();
|
|
209
|
+
let time = end - start;
|
|
210
|
+
let timePer = (time) / count * 1000 * 1000;
|
|
211
|
+
console.log(`Time per: ${timePer}ns, in ${time}ms`);
|
|
212
|
+
}
|
|
213
213
|
//benchmarkAddToStats();
|
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
import net from "net";
|
|
2
|
-
import { pipeline, PipelineTransform, PipelineTransformSource, Transform } from "stream";
|
|
3
|
-
|
|
4
|
-
export async function tcpLagProxy(config: {
|
|
5
|
-
localPort: number;
|
|
6
|
-
remoteHost: string;
|
|
7
|
-
remotePort: number;
|
|
8
|
-
// NOTE: Lag values between 1 and 10 are about the same, as setTimeout introduces a minimum delay.
|
|
9
|
-
// As a result lag values of 0 are about 2X faster than lag values of 1.
|
|
10
|
-
lag: number;
|
|
11
|
-
networkWriteSize?: { value: number };
|
|
12
|
-
networkReadSize?: { value: number };
|
|
13
|
-
networkWritePackets?: { value: number };
|
|
14
|
-
networkReadPackets?: { value: number };
|
|
15
|
-
}) {
|
|
16
|
-
const { localPort, remoteHost, remotePort, lag, networkWriteSize, networkReadSize, networkWritePackets, networkReadPackets } = config;
|
|
17
|
-
let server = net.createServer();
|
|
18
|
-
|
|
19
|
-
server.on("connection", async socket => {
|
|
20
|
-
// Swallow all errors, as the pipe should handle it anyways?
|
|
21
|
-
socket.on("error", () => { });
|
|
22
|
-
if (lag > 0) {
|
|
23
|
-
await new Promise(r => setTimeout(r, lag));
|
|
24
|
-
}
|
|
25
|
-
let remoteSocket = net.createConnection(remotePort, remoteHost);
|
|
26
|
-
remoteSocket.on("error", () => { });
|
|
27
|
-
|
|
28
|
-
const lagWrite = new Transform({
|
|
29
|
-
transform(chunk, encoding, callback) {
|
|
30
|
-
if (lag > 0) {
|
|
31
|
-
setTimeout(() => callback(undefined, chunk), lag);
|
|
32
|
-
} else {
|
|
33
|
-
callback(undefined, chunk);
|
|
34
|
-
}
|
|
35
|
-
},
|
|
36
|
-
});
|
|
37
|
-
const lagRead = new Transform({
|
|
38
|
-
transform(chunk, encoding, callback) {
|
|
39
|
-
if (lag > 0) {
|
|
40
|
-
setTimeout(() => callback(undefined, chunk), lag);
|
|
41
|
-
} else {
|
|
42
|
-
callback(undefined, chunk);
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
socket.pipe(lagWrite).pipe(remoteSocket);
|
|
48
|
-
remoteSocket.pipe(lagRead).pipe(socket);
|
|
49
|
-
|
|
50
|
-
socket.on("data", data => {
|
|
51
|
-
if (networkWriteSize) networkWriteSize.value += data.length;
|
|
52
|
-
if (networkWritePackets) networkWritePackets.value++;
|
|
53
|
-
});
|
|
54
|
-
remoteSocket.on("data", data => {
|
|
55
|
-
if (networkReadSize) networkReadSize.value += data.length;
|
|
56
|
-
if (networkReadPackets) networkReadPackets.value++;
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
server.listen(localPort);
|
|
60
|
-
return new Promise<void>((resolve, reject) => {
|
|
61
|
-
server.on("listening", () => resolve());
|
|
62
|
-
server.on("error", reject);
|
|
63
|
-
});
|
|
1
|
+
import net from "net";
|
|
2
|
+
import { pipeline, PipelineTransform, PipelineTransformSource, Transform } from "stream";
|
|
3
|
+
|
|
4
|
+
export async function tcpLagProxy(config: {
|
|
5
|
+
localPort: number;
|
|
6
|
+
remoteHost: string;
|
|
7
|
+
remotePort: number;
|
|
8
|
+
// NOTE: Lag values between 1 and 10 are about the same, as setTimeout introduces a minimum delay.
|
|
9
|
+
// As a result lag values of 0 are about 2X faster than lag values of 1.
|
|
10
|
+
lag: number;
|
|
11
|
+
networkWriteSize?: { value: number };
|
|
12
|
+
networkReadSize?: { value: number };
|
|
13
|
+
networkWritePackets?: { value: number };
|
|
14
|
+
networkReadPackets?: { value: number };
|
|
15
|
+
}) {
|
|
16
|
+
const { localPort, remoteHost, remotePort, lag, networkWriteSize, networkReadSize, networkWritePackets, networkReadPackets } = config;
|
|
17
|
+
let server = net.createServer();
|
|
18
|
+
|
|
19
|
+
server.on("connection", async socket => {
|
|
20
|
+
// Swallow all errors, as the pipe should handle it anyways?
|
|
21
|
+
socket.on("error", () => { });
|
|
22
|
+
if (lag > 0) {
|
|
23
|
+
await new Promise(r => setTimeout(r, lag));
|
|
24
|
+
}
|
|
25
|
+
let remoteSocket = net.createConnection(remotePort, remoteHost);
|
|
26
|
+
remoteSocket.on("error", () => { });
|
|
27
|
+
|
|
28
|
+
const lagWrite = new Transform({
|
|
29
|
+
transform(chunk, encoding, callback) {
|
|
30
|
+
if (lag > 0) {
|
|
31
|
+
setTimeout(() => callback(undefined, chunk), lag);
|
|
32
|
+
} else {
|
|
33
|
+
callback(undefined, chunk);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
const lagRead = new Transform({
|
|
38
|
+
transform(chunk, encoding, callback) {
|
|
39
|
+
if (lag > 0) {
|
|
40
|
+
setTimeout(() => callback(undefined, chunk), lag);
|
|
41
|
+
} else {
|
|
42
|
+
callback(undefined, chunk);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
socket.pipe(lagWrite).pipe(remoteSocket);
|
|
48
|
+
remoteSocket.pipe(lagRead).pipe(socket);
|
|
49
|
+
|
|
50
|
+
socket.on("data", data => {
|
|
51
|
+
if (networkWriteSize) networkWriteSize.value += data.length;
|
|
52
|
+
if (networkWritePackets) networkWritePackets.value++;
|
|
53
|
+
});
|
|
54
|
+
remoteSocket.on("data", data => {
|
|
55
|
+
if (networkReadSize) networkReadSize.value += data.length;
|
|
56
|
+
if (networkReadPackets) networkReadPackets.value++;
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
server.listen(localPort);
|
|
60
|
+
return new Promise<void>((resolve, reject) => {
|
|
61
|
+
server.on("listening", () => resolve());
|
|
62
|
+
server.on("error", reject);
|
|
63
|
+
});
|
|
64
64
|
}
|
package/src/storagePath.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import os from "os";
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import { lazy } from "./caching";
|
|
4
|
-
|
|
5
|
-
export const getAppFolder = lazy(() => {
|
|
6
|
-
const path = os.homedir() + "/socket-function/";
|
|
7
|
-
if (!fs.existsSync(path)) {
|
|
8
|
-
fs.mkdirSync(path);
|
|
9
|
-
}
|
|
10
|
-
return path;
|
|
1
|
+
import os from "os";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import { lazy } from "./caching";
|
|
4
|
+
|
|
5
|
+
export const getAppFolder = lazy(() => {
|
|
6
|
+
const path = os.homedir() + "/socket-function/";
|
|
7
|
+
if (!fs.existsSync(path)) {
|
|
8
|
+
fs.mkdirSync(path);
|
|
9
|
+
}
|
|
10
|
+
return path;
|
|
11
11
|
});
|