Index: runtime/bin/socket_patch.dart |
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart |
index 485d1e52f4e70dea5aaee162999e5364f17bee56..4f285503c20c4cf2a2bbe6ef5138b22e70e6e315 100644 |
--- a/runtime/bin/socket_patch.dart |
+++ b/runtime/bin/socket_patch.dart |
@@ -207,131 +207,6 @@ class _NetworkInterface implements NetworkInterface { |
} |
-class _Rate { |
- final int buckets; |
- final data; |
- int lastValue = 0; |
- int nextBucket = 0; |
- |
- _Rate(int buckets) : buckets = buckets, data = new List.filled(buckets, 0); |
- |
- void update(int value) { |
- data[nextBucket] = value - lastValue; |
- lastValue = value; |
- nextBucket = (nextBucket + 1) % buckets; |
- } |
- |
- int get rate { |
- int sum = data.fold(0, (prev, element) => prev + element); |
- return sum ~/ buckets; |
- } |
-} |
- |
-// Statics information for the observatory. |
-class _SocketStat { |
- _Rate readRate = new _Rate(5); |
- _Rate writeRate = new _Rate(5); |
- |
- void update(_NativeSocket socket) { |
- readRate.update(socket.totalRead); |
- writeRate.update(socket.totalWritten); |
- } |
-} |
- |
-class _SocketsObservatory { |
- static int socketCount = 0; |
- static Map sockets = new Map<_NativeSocket, _SocketStat>(); |
- static Timer timer; |
- |
- static add(_NativeSocket socket) { |
- if (socketCount == 0) startTimer(); |
- sockets[socket] = new _SocketStat(); |
- socketCount++; |
- } |
- |
- static remove(_NativeSocket socket) { |
- _SocketStat stats = sockets.remove(socket); |
- assert(stats != null); |
- socketCount--; |
- if (socketCount == 0) stopTimer(); |
- } |
- |
- static update(_) { |
- sockets.forEach((socket, stat) { |
- stat.update(socket); |
- }); |
- } |
- |
- static startTimer() { |
- if (timer != null) return; |
- // TODO(sgjesse): Enable the rate timer. |
- // timer = new Timer.periodic(new Duration(seconds: 1), update); |
- } |
- |
- static stopTimer() { |
- if (timer == null) return; |
- timer.cancel(); |
- timer = null; |
- } |
- |
- static String generateResponse() { |
- var response = new Map(); |
- response['type'] = 'SocketList'; |
- var members = new List(); |
- response['members'] = members; |
- sockets.forEach((socket, stat) { |
- var kind = |
- socket.isListening ? "LISTENING" : |
- socket.isPipe ? "PIPE" : |
- socket.isInternal ? "INTERNAL" : "NORMAL"; |
- var protocol = |
- socket.isTcp ? "tcp" : |
- socket.isUdp ? "udp" : ""; |
- var localAddress; |
- var localPort; |
- var remoteAddress; |
- var remotePort; |
- try { |
- localAddress = socket.address.address; |
- } catch (e) { |
- localAddress = "n/a"; |
- } |
- try { |
- localPort = socket.port; |
- } catch (e) { |
- localPort = "n/a"; |
- } |
- try { |
- remoteAddress = socket.remoteAddress.address; |
- } catch (e) { |
- remoteAddress = "n/a"; |
- } |
- try { |
- remotePort = socket.remotePort; |
- } catch (e) { |
- remotePort = "n/a"; |
- } |
- members.add({'type': 'Socket', 'kind': kind, 'protocol': protocol, |
- 'localAddress': localAddress, 'localPort': localPort, |
- 'remoteAddress': remoteAddress, 'remotePort': remotePort, |
- 'totalRead': socket.totalRead, |
- 'totalWritten': socket.totalWritten, |
- 'readPerSec': stat.readRate.rate, |
- 'writePerSec': stat.writeRate.rate}); |
- }); |
- return JSON.encode(response);; |
- } |
- |
- static String toJSON() { |
- try { |
- return generateResponse(); |
- } catch (e, s) { |
- return '{"type":"Error","text":"$e","stacktrace":"$s"}'; |
- } |
- } |
-} |
- |
- |
// The NativeFieldWrapperClass1 can not be used with a mixin, due to missing |
// implicit constructor. |
class _NativeSocketNativeWrapper extends NativeFieldWrapperClass1 {} |
@@ -432,14 +307,21 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject { |
bool writeEventIssued = false; |
bool writeAvailable = false; |
+ static final Stopwatch sw = new Stopwatch()..start(); |
// Statistics. |
int totalRead = 0; |
int totalWritten = 0; |
+ int readCount = 0; |
+ int writeCount = 0; |
+ double lastRead; |
+ double lastWrite; |
// The owner object is the object that the Socket is being used by, e.g. |
// a HttpServer, a WebSocket connection, a process pipe, etc. |
Object owner; |
+ static double get timestamp => sw.elapsedMicroseconds / 1000000.0; |
+ |
static Future<List<InternetAddress>> lookup( |
String host, {InternetAddressType type: InternetAddressType.ANY}) { |
return _IOService.dispatch(_SOCKET_LOOKUP, [host, type._value]) |
@@ -644,6 +526,8 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject { |
available -= result.length; |
totalRead += result.length; |
} |
+ readCount++; |
+ lastRead = timestamp; |
return result; |
} |
@@ -662,7 +546,10 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject { |
} else { |
available -= result.data.length; |
} |
+ totalRead += result.data.length; |
} |
+ readCount++; |
+ lastRead = timestamp; |
return result; |
} |
@@ -702,6 +589,8 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject { |
// Negate the result, as stated above. |
if (result < 0) result = -result; |
totalWritten += result; |
+ writeCount++; |
+ lastWrite = timestamp; |
return result; |
} |
@@ -718,6 +607,9 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject { |
scheduleMicrotask(() => reportError(result, "Send failed")); |
result = 0; |
} |
+ totalWritten += result; |
+ writeCount++; |
+ lastWrite = timestamp; |
return result; |
} |
@@ -733,6 +625,7 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject { |
socket.localPort = localPort; |
socket.address = address; |
totalRead += 1; |
+ lastRead = timestamp; |
return socket; |
} |
@@ -1092,7 +985,26 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject { |
r['readClosed'] = isClosedRead; |
r['writeClosed'] = isClosedWrite; |
r['closing'] = isClosing; |
- r['listening'] = isListening; |
+ r['fd'] = nativeGetSocketId(); |
+ if (owner != null) { |
+ r['owner'] = owner._toJSON(true); |
+ } |
+ return r; |
+ } |
+ |
+ Map _toJSONInternal(bool ref) { |
+ var name = 'Internal'; |
+ var r = { |
+ 'id': _servicePath, |
+ 'type': _serviceType(ref), |
+ 'name': name, |
+ 'user_name': name, |
+ 'kind': _JSONKind(), |
+ }; |
+ if (ref) { |
+ return r; |
+ } |
+ r['closing'] = isClosing; |
r['fd'] = nativeGetSocketId(); |
if (owner != null) { |
r['owner'] = owner._toJSON(true); |
@@ -1147,10 +1059,24 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject { |
} |
Map _toJSON(bool ref) { |
+ var map; |
if (isPipe) { |
- return _toJSONPipe(ref); |
- } |
- return _toJSONNetwork(ref); |
+ map = _toJSONPipe(ref); |
+ } else if (isInternal) { |
+ map = _toJSONInternal(ref); |
+ } else { |
+ map = _toJSONNetwork(ref); |
+ } |
+ if (!ref) { |
+ map['available'] = available; |
+ map['totalRead'] = totalRead; |
+ map['totalWritten'] = totalWritten; |
+ map['readCount'] = totalWritten; |
+ map['writeCount'] = writeCount; |
+ map['lastRead'] = lastRead; |
+ map['lastWrite'] = lastWrite; |
+ } |
+ return map; |
} |
void nativeSetSocketId(int id) native "Socket_SetSocketId"; |