Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: runtime/bin/socket_patch.dart

Issue 163903002: Prototype of I/O statistics for Observatory (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Addressed review comments Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 patch class RawServerSocket { 5 patch class RawServerSocket {
6 /* patch */ static Future<RawServerSocket> bind(address, 6 /* patch */ static Future<RawServerSocket> bind(address,
7 int port, 7 int port,
8 {int backlog: 0, 8 {int backlog: 0,
9 bool v6Only: false}) { 9 bool v6Only: false}) {
10 return _RawServerSocket.bind(address, port, backlog, v6Only); 10 return _RawServerSocket.bind(address, port, backlog, v6Only);
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after
198 final List<InternetAddress> addresses = []; 198 final List<InternetAddress> addresses = [];
199 199
200 _NetworkInterface(this.name, this.index); 200 _NetworkInterface(this.name, this.index);
201 201
202 String toString() { 202 String toString() {
203 return "NetworkInterface('$name', $addresses)"; 203 return "NetworkInterface('$name', $addresses)";
204 } 204 }
205 } 205 }
206 206
207 207
208 class _Rate {
209 final int buckets;
210 final data;
211 int lastValue = 0;
212 int nextBucket = 0;
213
214 _Rate(int buckets) : buckets = buckets, data = new List.filled(buckets, 0);
215
216 void update(int value) {
217 data[nextBucket] = value - lastValue;
218 lastValue = value;
219 nextBucket = (nextBucket + 1) % buckets;
220 }
221
222 int get rate {
223 int sum = data.fold(0, (prev, element) => prev + element);
224 return sum ~/ buckets;
225 }
226 }
227
228 // Statics information for the observatory.
229 class _SocketStat {
230 _Rate readRate = new _Rate(5);
231 _Rate writeRate = new _Rate(5);
232
233 void update(_NativeSocket socket) {
234 readRate.update(socket.totalRead);
235 writeRate.update(socket.totalWritten);
236 }
237 }
238
239 class _SocketsObservatory {
240 static int socketCount = 0;
241 static Map sockets = new Map<_NativeSocket, _SocketStat>();
242 static Timer timer;
243
244 static add(_NativeSocket socket) {
245 if (socketCount == 0) startTimer();
246 sockets[socket] = new _SocketStat();
247 socketCount++;
248 }
249
250 static remove(_NativeSicket socket) {
251 sockets.remove(socket);
Anders Johnsen 2014/02/19 16:14:34 assert it is in the map.
Søren Gjesse 2014/03/06 11:13:43 Done.
252 socketCount--;
253 if (socketCount == 0) stopTimer();
254 }
255
256 static update(_) {
257 sockets.forEach((socket, stat) {
258 stat.update(socket);
259 });
260 }
261
262 static startTimer() {
263 if (timer != null) return;
264 timer = new Timer.periodic(new Duration(seconds: 1), update);
265 }
266
267 static stopTimer() {
268 if (timer == null) return;
269 timer.cancel();
270 timer = null;
271 }
272
273 static String generateResponse() {
274 var response = new Map();
275 response['type'] = 'SocketList';
276 var members = new List();
277 response['members'] = members;
278 sockets.forEach((socket, stat) {
279 var kind =
280 socket.isListening ? "LISTENING" :
281 socket.isPipe ? "PIPE" :
282 socket.isInternal ? "INTERNAL" : "NORMAL";
283 var protocol =
284 socket.isTcp ? "tcp" :
285 socket.isUdp ? "udp" : "";
286 var localAddress;
287 var localPort;
288 var remoteAddress;
289 var remotePort;
290 try {
291 localAddress = socket.address.address;
292 } catch (e) {
293 localAddress = "n/a";
294 }
295 try {
296 localPort = socket.port;
297 } catch (e) {
298 localPort = "n/a";
299 }
300 try {
301 remoteAddress = socket.remoteAddress.address;
302 } catch (e) {
303 remoteAddress = "n/a";
304 }
305 try {
306 remotePort = socket.remotePort;
307 } catch (e) {
308 remotePort = "n/a";
309 }
310 members.add({'kind': kind, 'protocol': protocol,
Cutch 2014/02/19 16:05:13 Need a 'type': 'Socket' in this map.
Søren Gjesse 2014/03/06 11:13:43 Done.
311 'localAddress': localAddress, 'localPort': localPort,
312 'remoteAddress': remoteAddress, 'remotePort': remotePort,
313 'totalRead': socket.totalRead,
314 'totalWritten': socket.totalWritten,
315 'readPerSec': stat.readRate.rate,
316 'writePerSec': stat.writeRate.rate});
317 });
318 return JSON.encode(response);;
319 }
320
321 static String toJSON() {
322 try {
323 return generateResponse();
324 } catch (e, s) {
325 return '{"type":"Error","text":"$e","stacktrace":"$s"}';
326 }
327 }
328 }
329
330
208 // The _NativeSocket class encapsulates an OS socket. 331 // The _NativeSocket class encapsulates an OS socket.
209 class _NativeSocket extends NativeFieldWrapperClass1 { 332 class _NativeSocket extends NativeFieldWrapperClass1 {
210 // Bit flags used when communicating between the eventhandler and 333 // Bit flags used when communicating between the eventhandler and
211 // dart code. The EVENT flags are used to indicate events of 334 // dart code. The EVENT flags are used to indicate events of
212 // interest when sending a message from dart code to the 335 // interest when sending a message from dart code to the
213 // eventhandler. When receiving a message from the eventhandler the 336 // eventhandler. When receiving a message from the eventhandler the
214 // EVENT flags indicate the events that actually happened. The 337 // EVENT flags indicate the events that actually happened. The
215 // COMMAND flags are used to send commands from dart to the 338 // COMMAND flags are used to send commands from dart to the
216 // eventhandler. COMMAND flags are never received from the 339 // eventhandler. COMMAND flags are never received from the
217 // eventhandler. Additional flags are used to communicate other 340 // eventhandler. Additional flags are used to communicate other
(...skipping 13 matching lines...) Expand all
231 static const int FIRST_COMMAND = CLOSE_COMMAND; 354 static const int FIRST_COMMAND = CLOSE_COMMAND;
232 static const int LAST_COMMAND = SHUTDOWN_WRITE_COMMAND; 355 static const int LAST_COMMAND = SHUTDOWN_WRITE_COMMAND;
233 356
234 // Type flag send to the eventhandler providing additional 357 // Type flag send to the eventhandler providing additional
235 // information on the type of the file descriptor. 358 // information on the type of the file descriptor.
236 static const int LISTENING_SOCKET = 16; 359 static const int LISTENING_SOCKET = 16;
237 static const int PIPE_SOCKET = 17; 360 static const int PIPE_SOCKET = 17;
238 static const int TYPE_NORMAL_SOCKET = 0; 361 static const int TYPE_NORMAL_SOCKET = 0;
239 static const int TYPE_LISTENING_SOCKET = 1 << LISTENING_SOCKET; 362 static const int TYPE_LISTENING_SOCKET = 1 << LISTENING_SOCKET;
240 static const int TYPE_PIPE = 1 << PIPE_SOCKET; 363 static const int TYPE_PIPE = 1 << PIPE_SOCKET;
364 static const int TYPE_TYPE_MASK = TYPE_LISTENING_SOCKET | PIPE_SOCKET;
365
366 // Protocol flags.
367 static const int TCP_SOCKET = 18;
368 static const int UDP_SOCKET = 19;
369 static const int INTERNAL_SOCKET = 20;
370 static const int TYPE_TCP_SOCKET = 1 << TCP_SOCKET;
371 static const int TYPE_UDP_SOCKET = 1 << UDP_SOCKET;
372 static const int TYPE_INTERNAL_SOCKET = 1 << INTERNAL_SOCKET;
373 static const int TYPE_PROTOCOL_MASK =
374 TYPE_TCP_SOCKET | TYPE_UDP_SOCKET | TYPE_INTERNAL_SOCKET;
375
241 376
242 // Native port messages. 377 // Native port messages.
243 static const HOST_NAME_LOOKUP = 0; 378 static const HOST_NAME_LOOKUP = 0;
244 static const LIST_INTERFACES = 1; 379 static const LIST_INTERFACES = 1;
245 static const REVERSE_LOOKUP = 2; 380 static const REVERSE_LOOKUP = 2;
246 381
247 // Protocol flags. 382 // Protocol flags.
248 static const int PROTOCOL_IPV4 = 1 << 0; 383 static const int PROTOCOL_IPV4 = 1 << 0;
249 static const int PROTOCOL_IPV6 = 1 << 1; 384 static const int PROTOCOL_IPV6 = 1 << 1;
250 385
(...skipping 19 matching lines...) Expand all
270 405
271 int available = 0; 406 int available = 0;
272 407
273 bool sendReadEvents = false; 408 bool sendReadEvents = false;
274 bool readEventIssued = false; 409 bool readEventIssued = false;
275 410
276 bool sendWriteEvents = false; 411 bool sendWriteEvents = false;
277 bool writeEventIssued = false; 412 bool writeEventIssued = false;
278 bool writeAvailable = false; 413 bool writeAvailable = false;
279 414
415 // Statistics.
416 int totalRead = 0;
417 int totalWritten = 0;
418
280 static Future<List<InternetAddress>> lookup( 419 static Future<List<InternetAddress>> lookup(
281 String host, {InternetAddressType type: InternetAddressType.ANY}) { 420 String host, {InternetAddressType type: InternetAddressType.ANY}) {
282 return _IOService.dispatch(_SOCKET_LOOKUP, [host, type._value]) 421 return _IOService.dispatch(_SOCKET_LOOKUP, [host, type._value])
283 .then((response) { 422 .then((response) {
284 if (isErrorResponse(response)) { 423 if (isErrorResponse(response)) {
285 throw createError(response, "Failed host lookup: '$host'"); 424 throw createError(response, "Failed host lookup: '$host'");
286 } else { 425 } else {
287 return response.skip(1).map((result) { 426 return response.skip(1).map((result) {
288 var type = new InternetAddressType._from(result[0]); 427 var type = new InternetAddressType._from(result[0]);
289 return new _InternetAddress(result[1], host, result[2]); 428 return new _InternetAddress(result[1], host, result[2]);
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 throw new SocketException("Failed to create datagram socket", 563 throw new SocketException("Failed to create datagram socket",
425 osError: result, 564 osError: result,
426 address: address, 565 address: address,
427 port: port); 566 port: port);
428 } 567 }
429 if (port != 0) socket.localPort = port; 568 if (port != 0) socket.localPort = port;
430 return socket; 569 return socket;
431 }); 570 });
432 } 571 }
433 572
434 _NativeSocket.datagram(this.address) : typeFlags = TYPE_NORMAL_SOCKET; 573 _NativeSocket.datagram(this.address)
574 : typeFlags = TYPE_NORMAL_SOCKET | TYPE_UDP_SOCKET {
575 _SocketsObservatory.add(this);
Anders Johnsen 2014/02/19 16:14:34 Move to setListening, where eventPort == null.
Søren Gjesse 2014/03/06 11:13:43 Done.
576 }
435 577
436 _NativeSocket.normal() : typeFlags = TYPE_NORMAL_SOCKET; 578 _NativeSocket.normal() : typeFlags = TYPE_NORMAL_SOCKET | TYPE_TCP_SOCKET {
579 _SocketsObservatory.add(this);
580 }
437 581
438 _NativeSocket.listen() : typeFlags = TYPE_LISTENING_SOCKET; 582 _NativeSocket.listen() : typeFlags = TYPE_LISTENING_SOCKET | TYPE_TCP_SOCKET {
583 _SocketsObservatory.add(this);
584 }
439 585
440 _NativeSocket.pipe() : typeFlags = TYPE_PIPE; 586 _NativeSocket.pipe() : typeFlags = TYPE_PIPE {
587 _SocketsObservatory.add(this);
588 }
441 589
442 _NativeSocket.watch(int id) : typeFlags = TYPE_NORMAL_SOCKET { 590 _NativeSocket.watch(int id)
591 : typeFlags = TYPE_NORMAL_SOCKET | TYPE_INTERNAL_SOCKET {
443 isClosedWrite = true; 592 isClosedWrite = true;
444 nativeSetSocketId(id); 593 nativeSetSocketId(id);
594 _SocketsObservatory.add(this);
445 } 595 }
446 596
597 bool get isListening => (typeFlags & TYPE_LISTENING_SOCKET) != 0;
598 bool get isPipe => (typeFlags & TYPE_PIPE) != 0;
599 bool get isInternal => (typeFlags & TYPE_INTERNAL_SOCKET) != 0;
600 bool get isTcp => (typeFlags & TYPE_TCP_SOCKET) != 0;
601 bool get isUdp => (typeFlags & TYPE_UDP_SOCKET) != 0;
602
447 List<int> read(int len) { 603 List<int> read(int len) {
448 if (len != null && len <= 0) { 604 if (len != null && len <= 0) {
449 throw new ArgumentError("Illegal length $len"); 605 throw new ArgumentError("Illegal length $len");
450 } 606 }
451 if (isClosing || isClosed) return null; 607 if (isClosing || isClosed) return null;
452 var result = nativeRead(min(available, len == null ? available : len)); 608 var result = nativeRead(min(available, len == null ? available : len));
453 if (result is OSError) { 609 if (result is OSError) {
454 reportError(result, "Read failed"); 610 reportError(result, "Read failed");
455 return null; 611 return null;
456 } 612 }
457 if (result != null) available -= result.length; 613 if (result != null) available -= result.length;
614 totalRead += result.length;
Anders Johnsen 2014/02/19 16:14:34 put in '!= null'.
Søren Gjesse 2014/03/06 11:13:43 Done.
458 return result; 615 return result;
459 } 616 }
460 617
461 Datagram receive() { 618 Datagram receive() {
462 if (isClosing || isClosed) return null; 619 if (isClosing || isClosed) return null;
463 var result = nativeRecvFrom(); 620 var result = nativeRecvFrom();
464 if (result is OSError) { 621 if (result is OSError) {
465 reportError(result, "Receive failed"); 622 reportError(result, "Receive failed");
466 return null; 623 return null;
467 } 624 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 result = 0; 662 result = 0;
506 } 663 }
507 // The result may be negative, if we forced a short write for testing 664 // The result may be negative, if we forced a short write for testing
508 // purpose. In such case, don't mark writeAvailable as false, as we don't 665 // purpose. In such case, don't mark writeAvailable as false, as we don't
509 // know if we'll receive an event. It's better to just retry. 666 // know if we'll receive an event. It's better to just retry.
510 if (result >= 0 && result < bytes) { 667 if (result >= 0 && result < bytes) {
511 writeAvailable = false; 668 writeAvailable = false;
512 } 669 }
513 // Negate the result, as stated above. 670 // Negate the result, as stated above.
514 if (result < 0) result = -result; 671 if (result < 0) result = -result;
672 totalWritten += result;
515 return result; 673 return result;
516 } 674 }
517 675
518 int send(List<int> buffer, int offset, int bytes, 676 int send(List<int> buffer, int offset, int bytes,
519 InternetAddress address, int port) { 677 InternetAddress address, int port) {
520 if (isClosing || isClosed) return 0; 678 if (isClosing || isClosed) return 0;
521 _BufferAndStart bufferAndStart = 679 _BufferAndStart bufferAndStart =
522 _ensureFastAndSerializableByteData( 680 _ensureFastAndSerializableByteData(
523 buffer, offset, bytes); 681 buffer, offset, bytes);
524 var result = nativeSendTo( 682 var result = nativeSendTo(
525 bufferAndStart.buffer, bufferAndStart.start, bytes, 683 bufferAndStart.buffer, bufferAndStart.start, bytes,
526 address._in_addr, port); 684 address._in_addr, port);
527 if (result is OSError) { 685 if (result is OSError) {
528 scheduleMicrotask(() => reportError(result, "Send failed")); 686 scheduleMicrotask(() => reportError(result, "Send failed"));
529 result = 0; 687 result = 0;
530 } 688 }
531 return result; 689 return result;
532 } 690 }
533 691
534 _NativeSocket accept() { 692 _NativeSocket accept() {
535 // Don't issue accept if we're closing. 693 // Don't issue accept if we're closing.
536 if (isClosing || isClosed) return null; 694 if (isClosing || isClosed) return null;
537 var socket = new _NativeSocket.normal(); 695 var socket = new _NativeSocket.normal();
538 if (nativeAccept(socket) != true) return null; 696 if (nativeAccept(socket) != true) {
697 _SocketsObservatory.remove(socket);
Anders Johnsen 2014/02/19 16:14:34 This can be removed with above change.
Søren Gjesse 2014/03/06 11:13:43 Done.
698 return null;
699 }
539 socket.localPort = localPort; 700 socket.localPort = localPort;
540 socket.address = address; 701 socket.address = address;
702 totalRead += 1;
541 return socket; 703 return socket;
542 } 704 }
543 705
544 int get port { 706 int get port {
545 if (localPort != 0) return localPort; 707 if (localPort != 0) return localPort;
546 return localPort = nativeGetPort(); 708 return localPort = nativeGetPort();
547 } 709 }
548 710
549 int get remotePort { 711 int get remotePort {
550 return nativeGetRemotePeer()[1]; 712 return nativeGetRemotePeer()[1];
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
602 } 764 }
603 } 765 }
604 766
605 // Multiplexes socket events to the socket handlers. 767 // Multiplexes socket events to the socket handlers.
606 void multiplex(int events) { 768 void multiplex(int events) {
607 for (int i = FIRST_EVENT; i <= LAST_EVENT; i++) { 769 for (int i = FIRST_EVENT; i <= LAST_EVENT; i++) {
608 if (((events & (1 << i)) != 0)) { 770 if (((events & (1 << i)) != 0)) {
609 if ((i == CLOSED_EVENT || i == READ_EVENT) && isClosedRead) continue; 771 if ((i == CLOSED_EVENT || i == READ_EVENT) && isClosedRead) continue;
610 if (isClosing && i != DESTROYED_EVENT) continue; 772 if (isClosing && i != DESTROYED_EVENT) continue;
611 if (i == CLOSED_EVENT && 773 if (i == CLOSED_EVENT &&
612 typeFlags != TYPE_LISTENING_SOCKET && 774 !isListening &&
613 !isClosing && 775 !isClosing &&
614 !isClosed) { 776 !isClosed) {
615 isClosedRead = true; 777 isClosedRead = true;
616 issueReadEvent(); 778 issueReadEvent();
617 continue; 779 continue;
618 } 780 }
619 781
620 if (i == WRITE_EVENT) { 782 if (i == WRITE_EVENT) {
621 writeAvailable = true; 783 writeAvailable = true;
622 issueWriteEvent(delayed: false); 784 issueWriteEvent(delayed: false);
623 continue; 785 continue;
624 } 786 }
625 787
626 if (i == READ_EVENT && 788 if (i == READ_EVENT && !isListening) {
627 typeFlags != TYPE_LISTENING_SOCKET) {
628 var avail = nativeAvailable(); 789 var avail = nativeAvailable();
629 if (avail is int) { 790 if (avail is int) {
630 available = avail; 791 available = avail;
631 } else { 792 } else {
632 // Available failed. Mark socket as having data, to ensure read 793 // Available failed. Mark socket as having data, to ensure read
633 // events, and thus reporting of this error. 794 // events, and thus reporting of this error.
634 available = 1; 795 available = 1;
635 } 796 }
636 issueReadEvent(); 797 issueReadEvent();
637 continue; 798 continue;
638 } 799 }
639 800
640 var handler = eventHandlers[i]; 801 var handler = eventHandlers[i];
641 if (i == DESTROYED_EVENT) { 802 if (i == DESTROYED_EVENT) {
642 assert(!isClosed); 803 assert(!isClosed);
643 isClosed = true; 804 isClosed = true;
644 closeCompleter.complete(); 805 closeCompleter.complete();
645 disconnectFromEventHandler(); 806 disconnectFromEventHandler();
646 if (handler != null) handler(); 807 if (handler != null) handler();
808 _SocketsObservatory.remove(this);
647 continue; 809 continue;
648 } 810 }
649 811
650 if (i == ERROR_EVENT) { 812 if (i == ERROR_EVENT) {
651 if (!isClosing) { 813 if (!isClosing) {
652 reportError(nativeGetError(), ""); 814 reportError(nativeGetError(), "");
653 } 815 }
654 } else if (!isClosed) { 816 } else if (!isClosed) {
655 // If the connection is closed right after it's accepted, there's a 817 // If the connection is closed right after it's accepted, there's a
656 // chance the close-handler is not set. 818 // chance the close-handler is not set.
(...skipping 10 matching lines...) Expand all
667 eventHandlers[CLOSED_EVENT] = closed; 829 eventHandlers[CLOSED_EVENT] = closed;
668 eventHandlers[DESTROYED_EVENT] = destroyed; 830 eventHandlers[DESTROYED_EVENT] = destroyed;
669 } 831 }
670 832
671 void setListening({read: true, write: true}) { 833 void setListening({read: true, write: true}) {
672 sendReadEvents = read; 834 sendReadEvents = read;
673 sendWriteEvents = write; 835 sendWriteEvents = write;
674 if (read) issueReadEvent(); 836 if (read) issueReadEvent();
675 if (write) issueWriteEvent(); 837 if (write) issueWriteEvent();
676 if (eventPort == null) { 838 if (eventPort == null) {
677 int flags = typeFlags; 839 int flags = typeFlags & TYPE_TYPE_MASK;
678 if (!isClosedRead) flags |= 1 << READ_EVENT; 840 if (!isClosedRead) flags |= 1 << READ_EVENT;
679 if (!isClosedWrite) flags |= 1 << WRITE_EVENT; 841 if (!isClosedWrite) flags |= 1 << WRITE_EVENT;
680 sendToEventHandler(flags); 842 sendToEventHandler(flags);
681 } 843 }
682 } 844 }
683 845
684 Future close() { 846 Future close() {
685 if (!isClosing && !isClosed) { 847 if (!isClosing && !isClosed) {
686 sendToEventHandler(1 << CLOSE_COMMAND); 848 sendToEventHandler(1 << CLOSE_COMMAND);
687 isClosing = true; 849 isClosing = true;
(...skipping 899 matching lines...) Expand 10 before | Expand all | Expand 10 after
1587 1749
1588 Datagram _makeDatagram(List<int> data, 1750 Datagram _makeDatagram(List<int> data,
1589 String address, 1751 String address,
1590 List<int> in_addr, 1752 List<int> in_addr,
1591 int port) { 1753 int port) {
1592 return new Datagram( 1754 return new Datagram(
1593 data, 1755 data,
1594 new _InternetAddress(address, null, in_addr), 1756 new _InternetAddress(address, null, in_addr),
1595 port); 1757 port);
1596 } 1758 }
1759
1760 String _socketsStats() => _SocketsObservatory.toJSON();
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698