#!/bin/sh # To extract, remove the header and type "sh filename" # # This archive contains the following files: # # ./Imakefile # ./iperf.man # ./iperf.c # ./rect.c # ./seg.c # ./tester.c # ./text.c # ./rect.h # ./seg.h # ./tester.h # ./text.h # if `test ! -s ./Imakefile` then echo "writing ./Imakefile" sed 's/^X//' > ./Imakefile << '\End\Of\File\' XXCOMM XXCOMM iperf XXCOMM X X#ifdef InObjectCodeDir X XUse_libInterViews() XComplexProgramTarget(iperf) X X#define Obj(file) MakeObjectFromSrc(file) X#define ObjFlags(file,flags) MakeObjectFromSrcFlags(file,flags) X X/* X * iperf source files X */ X XObj(iperf) XObj(tester) XObj(rect) XObj(seg) XObj(text) X X#else X XMakeInObjectCodeDir() X X#endif \End\Of\File\ else echo "will not over write ./Imakefile" fi if `test ! -s ./iperf.man` then echo "writing ./iperf.man" sed 's/^X//' > ./iperf.man << '\End\Of\File\' X.TH iperf 1 "27 November 1991" "InterViews" "InterViews Reference Manual" X.SH NAME Xiperf \- interviews performance test program X.SH SYNTAX X\fBiperf\fP [ \fI-rect10 | -seg10 | -ftext\fP ] \fI-repeat\fP X.SH DESCRIPTION XThe Xiperf program runs a test and reports how fast it can be executed. It Xis somewhat simular to the x11perf program. Round trip time to the Xserver is factored out of the final time reported. It is insured that Xthe server has actually performed work requested by the pixel fetching Xscheme from x11perf. X.PP X.I iperf Xautomatically calibrates the number of repetitions of each test, Xso that each should take approximately the same length of time to run across Xservers of widely differing speeds. X.PP XAll timeing reports are for the smallest object involved. X.PP XThis program is based on the work of Joel McCormack. X.SH OPTIONS X.I iperf Xis based on interviews and Xlib, and Xaccepts the options listed below: X.TP 14 X.B \-rect10 X10x10 solid-filled rectangle. X.TP 14 X.B \-seg10 X10-pixel thin line segment. X.TP 14 X.B \-ftext XCharacter in 80-char line (6x13). X.SH AUTHOR XDave Sternlicht MIT \End\Of\File\ else echo "will not over write ./iperf.man" fi if `test ! -s ./iperf.c` then echo "writing ./iperf.c" sed 's/^X//' > ./iperf.c << '\End\Of\File\' X// -*- c++ -*- X// iperf: performance testor for interviews. X// dave sternlicht mit X consortium X X// interviews classes X#include X//#include X#include X#include X#include X#include X#include X X// iperf classes X#include "tester.h" X#include "rect.h" X#include "seg.h" X#include "text.h" X X#include X#include X#include X Xconst String PERFGEOM = "600x600+0+0"; Xconst Coord MARGIN_SIZE = 2.0; Xconst char* USESTRING = "Usage: iperf [-rect10 | -seg10 | -ftext] -repeat\n"; X Xstatic PropertyData props[] = { X { "*double_buffered", "off" }, // turn off double buffering for now... X { "*dpi", "72"}, X { "*repeat", "5"}, X { "*rect10", "off"}, X { "*seg10", "off"}, X { "*ftext", "off"}, X { nil } X}; X Xstatic OptionDesc options[] = { X {"-repeat", "*repeat", OptionValueNext}, X {"-rect10", "*rect10", OptionValueImplicit, "on"}, X {"-seg10", "*seg10", OptionValueImplicit, "on"}, X {"-ftext", "*ftext", OptionValueImplicit, "on"}, X { nil } X}; X Xvoid usage() { X fprintf(stderr, USESTRING); X exit(1); X} X X/* I want override-redirect and the geometry member of ManagedWindow X * but I can't do this because Managed and Popup Window inherit X * Window non-virtual!!!! X *class ManagedPopupWindow : public ManagedWindow, X *public PopupWindow { X *public: X * ManagedPopupWindow(Glyph* g) : ManagedWindow(g), PopupWindow(g) {}; X *}; X */ X Xint main(int argc, char** argv) { X Tester* tester; X Session* session = new Session("Itest", argc, argv, options, props); X Style* style = session->style(); X String s; X style->find_attribute("repeat", s); X int repeat; X s.convert(repeat); X if (style->value_is_on("rect10")) X tester = new RectTester(session, repeat); X else if (style->value_is_on("seg10")) X tester = new SegTester(session, repeat); X else if (style->value_is_on("ftext")) X tester = new TextTester(session, repeat); X else { X usage(); X } X Kit* kit = Kit::instance(); X// ManagedPopupWindow* w = new ManagedPopupWindow( X TransientWindow* w = new TransientWindow( X kit->outset_frame( X new Margin( X// new DebugGlyph( X tester, X// "tester", X// DebugGlyph::trace_request|DebugGlyph::trace_allocate X// ), X MARGIN_SIZE X ), X style X ) X ); X w->transient_for(w); X w->geometry(PERFGEOM); X X return session->run_window(w); X} X \End\Of\File\ else echo "will not over write ./iperf.c" fi if `test ! -s ./rect.c` then echo "writing ./rect.c" sed 's/^X//' > ./rect.c << '\End\Of\File\' X// -*- c++ -*- X// RectTester subclass X// dave sternlicht mit X consortium X X#include "rect.h" X XRectTester::RectTester(Session* s, int repeat) : Tester(s, repeat) { X objects_ = 1000; X} X Xvoid RectTester::proc(Canvas* c, int reps) const { X const Color* fg = black_; X int h, i, j; X float l, b, r, t; X for (h = 0; h != reps; h++) { X l = TEST_MARGIN_SIZE; X b = HEIGHT - TEST_MARGIN_SIZE - RECT_DIM; X r = RECT_DIM + TEST_MARGIN_SIZE; X t = HEIGHT - TEST_MARGIN_SIZE; X for (i = 0; i < RECT_COLS; i++) { X for (j = 0; j < RECT_ROWS; j++) { X c->fill_rect(l, b, r, t, fg); X t -= RECT_DIM + RECT_GAP; X b -= RECT_DIM + RECT_GAP; X } X l += RECT_DIM + RECT_GAP; X b = HEIGHT - TEST_MARGIN_SIZE - RECT_DIM; X r += RECT_DIM + RECT_GAP; X t = HEIGHT - TEST_MARGIN_SIZE; X } X X b = HEIGHT - TEST_MARGIN_SIZE - RECT_DIM; X t = HEIGHT - TEST_MARGIN_SIZE; X if (fg == black_) X fg = gray_; X else X fg = black_; X } X} X Xvoid RectTester::reportTimes(double time, int n, boolean average) const { X Tester::reportTimes(time, n, average); X printf("10x10 rectangle\n"); X} X X \End\Of\File\ else echo "will not over write ./rect.c" fi if `test ! -s ./seg.c` then echo "writing ./seg.c" sed 's/^X//' > ./seg.c << '\End\Of\File\' X// -*- c++ -*- X// SegTester subclass X// dave sternlicht mit X consortium X X#include "seg.h" X XSegTester::SegTester(Session* s, int repeat) : Tester(s, repeat) { X objects_ = 1000; X} X Xconst int LINE_SIZE = 10; Xconst int LINE_ROWS = 40; X Xvoid SegTester::proc(Canvas* c, int reps) const { X int size = LINE_SIZE; X int half = 1; X int h, i; X int rows; /* Number of rows filled in current column */ X int x, y; /* base of square to draw in */ X int x1, y1, x2, y2; /* offsets into square */ X int phase; /* how far into 0..8*size we are */ X int phaseinc; /* how much to increment phase at each segment */ X int size8; /* 8 * size */ X const Color* fg = black_; X X size8 = 8 * size; X half = (size + 19) / 20; X X /* All this x, x1, etc. stuff is to create a pattern that X (1) scans down the screen vertically, with each new segment going X into a square of size^2. X X (2) rotates the endpoints counter-clockwise around the square X X (3) rotates by ``large'' steps if we aren't going to paint enough X segments to get full coverage X */ X X X phaseinc = size8 / objects_; X if (phaseinc == 0) phaseinc = 1; X X for (h = 0; h != reps; h++) { X x = half; y = HEIGHT - half; X rows = 0; X phase = 0; X for (i = 0; i != objects_; i++) { X switch (phase / size) { X case 0: X x1 = 0; X y2 = 0; X x2 = size; X y1 = phase; X break; X case 1: X x1 = phase % size; X y2 = 0; X x2 = size; X y1 = size; X break; X case 2: X x1 = size; X y2 = 0; X x2 = size - phase % size; X y1 = size; X break; X case 3: X x1 = size; X y2 = phase % size; X x2 = 0; X y1 = size; X break; X case 4: X x1 = size; X y2 = size; X x2 = 0; X y1 = size - phase % size; X break; X case 5: X x1 = size - phase % size; X y2 = size; X x2 = 0; X y1 = 0; X break; X case 6: X x1 = 0; X y2 = size; X x2 = phase % size; X y1 = 0; X break; X case 7: X x1 = 0; X y2 = size - phase % size; X x2 = size; X y1 = 0; X break; X } /* end switch */ X X c->new_path(); X c->move_to(x + x1, y + y1); X c->line_to(x + x2, y + y2); X c->close_path(); X c->stroke(fg, brush_); X /* Change square to draw segment in */ X rows++; X y -= size; X if (y <= size + half || rows == LINE_ROWS) { X /* Go to next column */ X rows = 0; X y = HEIGHT - half; X x += size; X if (x >= WIDTH - size - half) { X x = half; X } X } X X /* Increment phase */ X phase += phaseinc; X if (phase >= size8) phase -= size8; X } X if (fg == black_) X fg = gray_; X else X fg = black_; X } X}; X Xvoid SegTester::reportTimes(double time, int n, boolean average) const { X Tester::reportTimes(time, n, average); X printf("10-pixel line segment\n"); X} X X \End\Of\File\ else echo "will not over write ./seg.c" fi if `test ! -s ./tester.c` then echo "writing ./tester.c" sed 's/^X//' > ./tester.c << '\End\Of\File\' X// -*- c++ -*- X// Interviews tester class X// dave sternlicht mit X consortium X X#include "tester.h" X X// X// Tester base class X// X XTester::Tester(Session* ses, int repeat) : Glyph() { X alloc_ = new Allocation(); X ses_ = ses; X style_ = ses_->style(); X dpy_ = ses_->default_display(); X brush_ = new Brush(BRUSH_SIZE); X black_ = Color::lookup(ses_->default_display(), "black"); X gray_ = Color::lookup(ses_->default_display(), "gray"); X Resource::ref(black_); X Resource::ref(gray_); X syncTime_ = 0.0; X repeat_ = repeat; X} X Xvoid Tester::allocate(Canvas* c, const Allocation& a, Extension& e) { X Glyph::allocate(c, a, e); X *alloc_ = a; X canvas_ = c; X} X XTester::~Tester() { X Resource::unref(black_); Resource::unref(gray_); X} X Xvoid Tester::init(Canvas* c, int reps) { X c->fill_rect(alloc_->left(), alloc_->bottom(), X alloc_->right(), alloc_->top(), gray_); X dpy_->flush(); X} X Xint Tester::calibrateSyncTest(int seconds, X double* usecperobj, int objects) const { X const double goal = 2500000.0; // Try to get up to 2.5 seconds X const double enough = 2000000.0; // But settle for 2.0 seconds X const double tick = 10000.0; // Assume clock not faster than .01 seconds X int reps = 1; X double usecs = 0.0; X int exponent; X // Attempt to get an idea how long each rep lasts by getting enough X // reps to last more than enough. Then scale that up to the number of X // seconds desired. X for (;;) { X hardwareSync(canvas_); X initTimes(); X doHardwareSync(canvas_, reps); X hardwareSync(canvas_); X usecs += elapsedTime(syncTime_); X X /* Did we go long enough? */ X if (usecs >= enough) break; X X /* Don't let too short a clock make new reps wildly high */ X if (usecs < tick) usecs = tick; X X /* Try to get up to goal seconds. */ X reps = (int) (goal * (double)reps / usecs) + 1; X } X *usecperobj = usecs / (double) (reps * objects); X reps = (int) ((double)seconds * 1000000.0 * (double)reps / usecs) + 1; X X /* Now round reps up to 1 digit accuracy, so we don't get stupid-looking X numbers of repetitions. */ X reps--; X exponent = 1; X while (reps > 9) { X reps /= 10; X exponent *= 10; X } X reps = (reps + 1) * exponent; X printf("Sync time adjustment is %6.4f msecs.\n\n", *usecperobj/1000); X return reps; X} X Xint Tester::calibrateTest(int seconds, double* usecperobj, X int objects) const { X const double goal = 2500000.0; // Try to get up to 2.5 seconds X const double enough = 2000000.0; // But settle for 2.0 seconds X const double tick = 10000.0; // Assume clock not faster than .01 seconds X int reps = 1; X double usecs = 0.0; X int exponent; X printf("calibrating...\n"); X // Attempt to get an idea how long each rep lasts by getting enough X // reps to last more than enough. Then scale that up to the number of X // seconds desired. X for (;;) { X // initialization changes an object by definition so cast it non-const. X ((Tester*)this)->init(canvas_, reps); X hardwareSync(canvas_); X initTimes(); X proc(canvas_, reps); X hardwareSync(canvas_); X usecs += elapsedTime(syncTime_); X X /* Did we go long enough? */ X if (usecs >= enough) break; X X /* Don't let too short a clock make new reps wildly high */ X if (usecs < tick) usecs = tick; X X /* Try to get up to goal seconds. */ X reps = (int) (goal * (double)reps / usecs) + 1; X } X *usecperobj = usecs / (double) (reps * objects); X reps = (int) ((double)seconds * 1000000.0 * (double)reps / usecs) + 1; X X /* Now round reps up to 1 digit accuracy, so we don't get stupid-looking X numbers of repetitions. */ X reps--; X exponent = 1; X while (reps > 9) { X reps /= 10; X exponent *= 10; X } X reps = (reps + 1) * exponent; X X return reps; X} X Xvoid Tester::draw(Canvas* c, const Allocation& a) const { X double usecs = 0.0; X int reps = 1; X X // calibrate sync time X calibrateSyncTest(1, &((Tester*)this)->syncTime_, 1); X X // do the test X processTest(); X X exit(0); X} X Xvoid Tester::processTest() const { X int j, reps; X double time, totalTime = 0; X reps = calibrateTest(5, &time, objects_); X printf("doing test...\n"); X for (j = 0; j != repeat_; j++) { X time = doTest(reps); X totalTime += time; X reportTimes(time, reps * objects_, False); X } X if (repeat_ > 1) X reportTimes(totalTime, repeat_ * reps * objects_, True); X} X Xdouble Tester::doTest(int reps) const { X double time; X ((Tester*)this)->init(canvas_, reps); X hardwareSync(canvas_); X initTimes(); X proc(canvas_, reps); X hardwareSync(canvas_); X time = elapsedTime(syncTime_); X cleanup(canvas_); X return time; X} X Xdouble Tester::roundTo3Digits(double d) const X{ X /* It's kind of silly to print out things like ``193658.4/sec'' so just X junk all but 3 most significant digits. */ X X double exponent, sign; X X exponent = 1.0; X /* the code below won't work if d should happen to be non-positive. */ X if (d < 0.0) { X d = -d; X sign = -1.0; X } else X sign = 1.0; X if (d >= 1000.0) { X do { X exponent *= 10.0; X } while (d/exponent >= 1000.0); X d = (double)((int) (d/exponent + 0.5)); X d *= exponent; X } else { X if (d != 0.0) { X while (d*exponent < 100.0) { X exponent *= 10.0; X } X } X d = (double)((int) (d*exponent + 0.5)); X d /= exponent; X } X return d * sign; X} X Xvoid Tester::reportTimes(double usecs, int n, boolean average) const { X double msecsperobj, objspersec; X X msecsperobj = usecs / (1000.0 * (double)n); X objspersec = (double) n * 1000000.0 / usecs; X X // Round obj/sec to 3 significant digits. Leave msec untouched, to X // allow averaging results from several repetitions. X objspersec = roundTo3Digits(objspersec); X X if (average) X printf("%6d trep @ %7.4f msec (%6.1f/sec): ", X n, msecsperobj, objspersec); X else printf("%6d reps @ %7.4f msec (%6.1f/sec): ", X n, msecsperobj, objspersec); X} X Xvoid Tester::doHardwareSync(Canvas* c, int reps) const { X int i; X for (i = 0; i != reps; i++) X hardwareSync(c); X} X Xvoid Tester::hardwareSync(Canvas* c) const{ X XImage *image; X image = XGetImage(dpy_->rep()->display_, X c->rep()->window_->rep()->xwindow_, X WIDTH-1, HEIGHT-1, 1, 1, ~0, ZPixmap); X XDestroyImage(image); X} X Xstatic struct timeval start; X Xvoid Tester::initTimes() const X{ X struct timezone foo; X gettimeofday(&start, &foo); X} X Xdouble Tester::elapsedTime(double correction) const X{ X struct timeval stop; X struct timezone foo; X X gettimeofday(&stop, &foo); X if (stop.tv_usec < start.tv_usec) { X stop.tv_usec += 1000000; X stop.tv_sec -= 1; X } X return (double)(stop.tv_usec - start.tv_usec) + X (1000000.0 * (double)(stop.tv_sec - start.tv_sec)) - correction; X} X X X \End\Of\File\ else echo "will not over write ./tester.c" fi if `test ! -s ./text.c` then echo "writing ./text.c" sed 's/^X//' > ./text.c << '\End\Of\File\' X// -*- c++ -*- X// TextTester subclass X// dave sternlicht mit X consortium X X#include "text.h" X XCoord ypos; X XTextTester::TextTester(Session* s, int repeat) : Tester(s, repeat) { X} X Xvoid TextTester::init(Canvas* c, int reps) { X c->fill_rect(alloc_->left(), alloc_->bottom(), alloc_->right(), X alloc_->top(), gray_); X dpy_->flush(); X X int i, j; X char ch; X objects_ = 80; X font_ = new Font(FONT); X ypos = XPOS; X height_ = (font_->ascent() + font_->descent()) + 1; X X charsPerLine_ = CHARS_PER_LINE; X charsPerLine_ = (charsPerLine_ + 3) & ~3; X X totalLines_ = '\177' - ' ' + 1; // 177 = DEL X if (totalLines_ > reps) totalLines_ = reps; X X charBuf_ = new CharStruct*[totalLines_]; X X for (i = 0; i != totalLines_; i++) { X charBuf_[i] = new CharStruct[charsPerLine_]; X ch = i + ' '; X for (j = 0; j != charsPerLine_; j++) { X charBuf_[i][j].c = ch; X charBuf_[i][j].w = font_->width(ch); X if (ch == '\177') ch = ' '; else ch++; X } X } X} X Xstatic int line = 0; Xstatic int startLine = 0; X Xvoid TextTester::proc(Canvas* c, int reps) const { X int i, j; X Coord charx, chary; X for (i = 0; i != reps; i++) { X charx = 0.0; chary = 0.0; X for (j=0; jcharacter(font_, charBuf_[line][j].c, charBuf_[line][j].w, X black_, charx, ypos); X charx += charBuf_[line][j].w; X } X ypos -= height_; X if (ypos < height_) { X /* Wraparound to bottom of window */ X ypos = XPOS; X startLine = (startLine + 17) % totalLines_; X line = startLine; X } X line = (line + 1) % totalLines_; X } X} X XTextTester::~TextTester() { X int i; X for (i = 0; i != totalLines_; i++) X delete[] charBuf_[i]; X delete[] charBuf_; X} X Xvoid TextTester::reportTimes(double time, int n, boolean average) const { X Tester::reportTimes(time, n, average); X printf("Char in 80-char line (6x13)\n"); X} \End\Of\File\ else echo "will not over write ./text.c" fi if `test ! -s ./rect.h` then echo "writing ./rect.h" sed 's/^X//' > ./rect.h << '\End\Of\File\' X// -*- c++ -*- X// RectTester subclass X// dave sternlicht mit X consortium X X#ifndef rect_h X#define rect_h X X#include "tester.h" X Xclass RectTester : public Tester { Xpublic: X RectTester(Session*, int); X virtual void proc(Canvas*, int) const; Xprotected: X virtual void reportTimes(double, int, boolean) const; X}; X X#endif \End\Of\File\ else echo "will not over write ./rect.h" fi if `test ! -s ./seg.h` then echo "writing ./seg.h" sed 's/^X//' > ./seg.h << '\End\Of\File\' X// -*- c++ -*- X// SegTester subclass X// dave sternlicht mit X consortium X X#ifndef line_h X#define line_h X X#include "tester.h" X Xclass SegTester : public Tester { Xpublic: X SegTester(Session*, int); X virtual void proc(Canvas*, int) const; Xprotected: X virtual void reportTimes(double, int, boolean) const; X}; X X#endif \End\Of\File\ else echo "will not over write ./seg.h" fi if `test ! -s ./tester.h` then echo "writing ./tester.h" sed 's/^X//' > ./tester.h << '\End\Of\File\' X// -*- c++ -*- X// Interviews tester classes. X// dave sternlicht -- mit x consortium X// X X#ifndef tester_h X#define tester_h X X#include X#include X#include X#include X#include X#include X X#include X#include X#include X#include X#include X#include X X#include X#include X#include X Xconst int WIDTH = 600; Xconst int HEIGHT = 600; Xconst Coord BRUSH_SIZE = 1.0; Xconst Coord TEST_MARGIN_SIZE = 4.0; Xconst Coord RECT_DIM = 10.0; Xconst Coord RECT_GAP = 1.0; Xconst int RECT_ROWS = 40; Xconst int RECT_COLS = 25; Xconst String FONT = "6x13"; Xconst Coord XPOS = HEIGHT - 20.0; Xconst int CHARS_PER_LINE = 80; Xconst int COLLUMS = 96; X Xclass Tester : public Glyph { Xpublic: X Tester(Session*, int); X virtual ~Tester(); X virtual void init(Canvas*, int); X virtual void proc(Canvas*, int) const {}; X virtual void cleanup(Canvas*) const {}; X virtual void allocate(Canvas*, const Allocation&, Extension&); X virtual void draw(Canvas*, const Allocation&) const; Xprotected: X Allocation* alloc_; X Brush* brush_; X const Color* gray_; X const Color* black_; X Canvas* canvas_; X Display* dpy_; X Session* ses_; X Style* style_; X Transformer* trans_; X double syncTime_; X int calibrateSyncTest(int, double*, int) const; X int calibrateTest(int, double*, int) const; X void processTest() const; X double doTest(int) const; X void doHardwareSync(Canvas*, int) const; X void hardwareSync(Canvas*) const; X void initTimes() const; X double elapsedTime(double) const; X virtual void reportTimes(double, int, boolean) const; X double roundTo3Digits(double) const; X boolean flip_; X int objects_; X int repeat_; X}; X X#endif tester_h \End\Of\File\ else echo "will not over write ./tester.h" fi if `test ! -s ./text.h` then echo "writing ./text.h" sed 's/^X//' > ./text.h << '\End\Of\File\' X// -*- c++ -*- X// RectTester subclass X// dave sternlicht mit X consortium X X#ifndef text_h X#define text_h X X#include "tester.h" X Xtypedef struct {char c; Coord w;} CharStruct; X Xclass TextTester : public Tester { Xpublic: X TextTester(Session*, int); X virtual void init(Canvas*, int); X virtual void proc(Canvas*, int) const; X virtual ~TextTester(); Xprotected: X virtual void reportTimes(double, int, boolean) const; Xprivate: X Font* font_; X CharStruct** charBuf_; X Coord height_; X int charsPerLine_, totalLines_; X}; X X#endif \End\Of\File\ else echo "will not over write ./text.h" fi echo "Finished archive 1 of 1" exit