1235368Sgnn#!/usr/sbin/dtrace -s 2/* 3 * wpm.d - Measure words per minute of typing. 4 * Written in DTrace (Solaris 10 3/05). 5 * 6 * $Id: wpm.d 52 2007-09-24 04:28:01Z brendan $ 7 * 8 * USAGE: wpm.d commandname 9 * eg, 10 * wpm.d bash 11 * wpm.d vim 12 * 13 * This script assumes that keystrokes arrive one at a time on STDIN. This 14 * isn't the case for all processes that read keyboard input (eg, sh). 15 * 16 * COPYRIGHT: Copyright (c) 2007 Brendan Gregg. 17 * 18 * CDDL HEADER START 19 * 20 * The contents of this file are subject to the terms of the 21 * Common Development and Distribution License, Version 1.0 only 22 * (the "License"). You may not use this file except in compliance 23 * with the License. 24 * 25 * You can obtain a copy of the license at Docs/cddl1.txt 26 * or http://www.opensolaris.org/os/licensing. 27 * See the License for the specific language governing permissions 28 * and limitations under the License. 29 * 30 * CDDL HEADER END 31 * 32 * 05-Aug-2007 Brendan Gregg Created this. 33 */ 34 35#pragma D option quiet 36#pragma D option switchrate=10 37#pragma D option defaultargs 38 39inline int STDIN = 0; 40 41enum tracing_state { 42 BEGIN, 43 TRACING 44}; 45 46dtrace:::BEGIN 47/$$1 == ""/ 48{ 49 trace("USAGE: wpm.d commandname\n"); 50 trace(" eg,\n"); 51 trace(" wpm.d bash\n"); 52 trace(" wpm.d vim\n"); 53 exit(1); 54} 55 56dtrace:::BEGIN 57{ 58 state = BEGIN; 59 keys = 0; 60 words = 0; 61 wordsize = 0; 62 countdown = 5; 63 last = 0; 64 printf("Measuring will start in : %2d seconds", countdown); 65} 66 67profile:::tick-1sec 68/--countdown >= 0/ 69{ 70 printf("\b\b\b\b\b\b\b\b\b\b%2d seconds", countdown); 71} 72 73profile:::tick-1sec 74/state == BEGIN && countdown == -1/ 75{ 76 state = TRACING; 77 countdown = 60; 78 printf("\nMeasuring will stop in : %2d seconds", countdown); 79} 80 81syscall::read:entry 82/state == TRACING && execname == $$1 && arg0 == STDIN/ 83{ 84 self->buf = arg1; 85} 86 87syscall::read:return 88/self->buf && last/ 89{ 90 this->elapsed = (timestamp - last) / 1000000; 91 @dist = quantize(this->elapsed); 92 @avg = avg(this->elapsed); 93 @min = min(this->elapsed); 94 @max = max(this->elapsed); 95} 96 97syscall::read:return 98/self->buf/ 99{ 100 keys++; 101 wordsize++; 102 this->key = stringof(copyin(self->buf, arg0)); 103 last = timestamp; 104} 105 106syscall::read:return 107/self->buf && (this->key == " " || this->key == "\n" || this->key == "\r") && 108 wordsize == 1/ 109{ 110 /* recurring space */ 111 wordsize = 0; 112 self->buf = 0; 113} 114 115syscall::read:return 116/self->buf && (this->key == " " || this->key == "\n" || this->key == "\r")/ 117{ 118 words++; 119 @sizes = lquantize(wordsize - 1, 0, 32, 1); 120 wordsize = 0; 121} 122 123syscall::read:return 124/self->buf/ 125{ 126 self->buf = 0; 127} 128 129profile:::tick-1sec 130/state == TRACING && countdown == -1/ 131{ 132 printf("\n\nCharacters typed : %d\n", keys); 133 printf("Words per minute : %d\n\n", words); 134 135 printa("Minimum keystroke latency : %@d ms\n", @min); 136 printa("Average keystroke latency : %@d ms\n", @avg); 137 printa("Maximum keystroke latency : %@d ms\n\n", @max); 138 139 printa("Word size distribution (letters),\n%@d\n", @sizes); 140 printa("Keystroke latency distribution (ms),\n%@d\n", @dist); 141 142 exit(0); 143} 144