1N/A#!/usr/sbin/dtrace -s
1N/A/*
1N/A * wpm.d - Measure words per minute of typing.
1N/A * Written in DTrace (Solaris 10 3/05).
1N/A *
1N/A * $Id: wpm.d 52 2007-09-24 04:28:01Z brendan $
1N/A *
1N/A * USAGE: wpm.d commandname
1N/A * eg,
1N/A * wpm.d bash
1N/A * wpm.d vim
1N/A *
1N/A * This script assumes that keystrokes arrive one at a time on STDIN. This
1N/A * isn't the case for all processes that read keyboard input (eg, sh).
1N/A *
1N/A * COPYRIGHT: Copyright (c) 2007 Brendan Gregg.
1N/A *
1N/A * CDDL HEADER START
1N/A *
1N/A * The contents of this file are subject to the terms of the
1N/A * Common Development and Distribution License, Version 1.0 only
1N/A * (the "License"). You may not use this file except in compliance
1N/A * with the License.
1N/A *
1N/A * You can obtain a copy of the license at Docs/cddl1.txt
1N/A * or http://www.opensolaris.org/os/licensing.
1N/A * See the License for the specific language governing permissions
1N/A * and limitations under the License.
1N/A *
1N/A * CDDL HEADER END
1N/A *
1N/A * 05-Aug-2007 Brendan Gregg Created this.
1N/A */
1N/A
1N/A#pragma D option quiet
1N/A#pragma D option switchrate=10
1N/A#pragma D option defaultargs
1N/A
1N/Ainline int STDIN = 0;
1N/A
1N/Aenum tracing_state {
1N/A BEGIN,
1N/A TRACING
1N/A};
1N/A
1N/Adtrace:::BEGIN
1N/A/$$1 == ""/
1N/A{
1N/A trace("USAGE: wpm.d commandname\n");
1N/A trace(" eg,\n");
1N/A trace(" wpm.d bash\n");
1N/A trace(" wpm.d vim\n");
1N/A exit(1);
1N/A}
1N/A
1N/Adtrace:::BEGIN
1N/A{
1N/A state = BEGIN;
1N/A keys = 0;
1N/A words = 0;
1N/A wordsize = 0;
1N/A countdown = 5;
1N/A last = 0;
1N/A printf("Measuring will start in : %2d seconds", countdown);
1N/A}
1N/A
1N/Aprofile:::tick-1sec
1N/A/--countdown >= 0/
1N/A{
1N/A printf("\b\b\b\b\b\b\b\b\b\b%2d seconds", countdown);
1N/A}
1N/A
1N/Aprofile:::tick-1sec
1N/A/state == BEGIN && countdown == -1/
1N/A{
1N/A state = TRACING;
1N/A countdown = 60;
1N/A printf("\nMeasuring will stop in : %2d seconds", countdown);
1N/A}
1N/A
1N/Asyscall::read:entry
1N/A/state == TRACING && execname == $$1 && arg0 == STDIN/
1N/A{
1N/A self->buf = arg1;
1N/A}
1N/A
1N/Asyscall::read:return
1N/A/self->buf && last/
1N/A{
1N/A this->elapsed = (timestamp - last) / 1000000;
1N/A @dist = quantize(this->elapsed);
1N/A @avg = avg(this->elapsed);
1N/A @min = min(this->elapsed);
1N/A @max = max(this->elapsed);
1N/A}
1N/A
1N/Asyscall::read:return
1N/A/self->buf/
1N/A{
1N/A keys++;
1N/A wordsize++;
1N/A this->key = stringof(copyin(self->buf, arg0));
1N/A last = timestamp;
1N/A}
1N/A
1N/Asyscall::read:return
1N/A/self->buf && (this->key == " " || this->key == "\n" || this->key == "\r") &&
1N/A wordsize == 1/
1N/A{
1N/A /* recurring space */
1N/A wordsize = 0;
1N/A self->buf = 0;
1N/A}
1N/A
1N/Asyscall::read:return
1N/A/self->buf && (this->key == " " || this->key == "\n" || this->key == "\r")/
1N/A{
1N/A words++;
1N/A @sizes = lquantize(wordsize - 1, 0, 32, 1);
1N/A wordsize = 0;
1N/A}
1N/A
1N/Asyscall::read:return
1N/A/self->buf/
1N/A{
1N/A self->buf = 0;
1N/A}
1N/A
1N/Aprofile:::tick-1sec
1N/A/state == TRACING && countdown == -1/
1N/A{
1N/A printf("\n\nCharacters typed : %d\n", keys);
1N/A printf("Words per minute : %d\n\n", words);
1N/A
1N/A printa("Minimum keystroke latency : %@d ms\n", @min);
1N/A printa("Average keystroke latency : %@d ms\n", @avg);
1N/A printa("Maximum keystroke latency : %@d ms\n\n", @max);
1N/A
1N/A printa("Word size distribution (letters),\n%@d\n", @sizes);
1N/A printa("Keystroke latency distribution (ms),\n%@d\n", @dist);
1N/A
1N/A exit(0);
1N/A}