Merge lp:~compiz-team/compiz-bench-plugin/compiz-bench-plugin.fix_898548 into lp:compiz-bench-plugin

Proposed by Sam Spilsbury on 2011-12-05
Status: Merged
Merged at revision: 42
Proposed branch: lp:~compiz-team/compiz-bench-plugin/compiz-bench-plugin.fix_898548
Merge into: lp:compiz-bench-plugin
Diff against target: 491 lines (+171/-120)
2 files modified
src/bench.cpp (+147/-114)
src/bench.h (+24/-6)
To merge this branch: bzr merge lp:~compiz-team/compiz-bench-plugin/compiz-bench-plugin.fix_898548
Reviewer Review Type Date Requested Status
Daniel van Vugt 2011-12-05 Approve on 2011-12-05
Sam Spilsbury Approve on 2011-12-05
Review via email: mp+84433@code.launchpad.net

Description of the change

Redesigned Benchmark so that it doesn't affect its own results (LP: #898548)

Benchmark contained several design flaws that made it inaccurate, including:

  * A positive feedback loop meant the frame rate got stuck at maximum while benchmark was visible.
  * While stuck at maximum frame rate it was constantly damaging the entire screen instead of just its own region, which made the desktop noticeably laggy.
  * The method for smoothing used infinite decay, so was affected by its previous values from a long time ago. The new smoothing method is only affected by the past 2 seconds, for up-to-date accuracy.
  * The frame rate reported and rate of smoothing depended on how often the benchmark was redrawn. The new code ensures that the measured frame rate is not affected by how often it is reported on screen.
  * Colour: The old code represented a low frame rate as red (bad) and high as green. Actually, a low frame rate is normal on an idle desktop and good. So the colour has been reversed; low=green, high=red.

Re-proposal of https://code.launchpad.net/~vanvugt/compiz-plugins-extra/fix-898548-trunk/+merge/84236

To post a comment you must log in.
Sam Spilsbury (smspillaz) :
review: Approve
Daniel van Vugt (vanvugt) wrote :

Still looks good :)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/bench.cpp'
2--- src/bench.cpp 2010-07-02 06:30:32 +0000
3+++ src/bench.cpp 2011-12-05 05:01:23 +0000
4@@ -7,6 +7,9 @@
5 * Copyright : (C) 2006 by Dennis Kasprzyk
6 * E-mail : onestone@beryl-project.org
7 *
8+ * New frame rate measurement algorithm:
9+ * Copyright (c) 2011 Daniel van Vugt <vanvugt@gmail.com>
10+ *
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14@@ -24,73 +27,117 @@
15
16 COMPIZ_PLUGIN_20090315 (bench, BenchPluginVTable)
17
18+#define TEX_WIDTH 512
19+#define TEX_HEIGHT 256
20+
21 void
22 BenchScreen::preparePaint (int msSinceLastPaint)
23 {
24- float nRrVal;
25- float ratio = 0.05;
26- int timediff;
27-
28 struct timeval now;
29-
30 gettimeofday (&now, 0);
31
32- timediff = TIMEVALDIFF (&now, &mLastRedraw);
33-
34- nRrVal = MIN (1.1,
35- (float) cScreen->optimalRedrawTime () / (float) timediff);
36-
37- mRrVal = (mRrVal * (1.0 - ratio) ) + (nRrVal * ratio);
38-
39- mFps = (mFps * (1.0 - ratio) ) +
40- (1000000.0 / TIMEVALDIFFU (&now, &mLastRedraw) * ratio);
41-
42+ int timediff = TIMEVALDIFFU (&now, &mLastRedraw);
43+ mSample[mFrames % MAX_SAMPLES] = timediff;
44+ timediff /= 1000;
45+ mFrames++;
46 mLastRedraw = now;
47
48 if (optionGetOutputConsole () && mActive)
49 {
50- mFrames++;
51- mCtime += timediff;
52-
53- if (mCtime > optionGetConsoleUpdateTime () * 1000)
54+ int dTime = TIMEVALDIFF (&now, &mLastPrint);
55+ if (dTime > optionGetConsoleUpdateTime () * 1000)
56 {
57- printf ("[BENCH] : %.0f frames in %.1f seconds = %.3f FPS\n",
58- mFrames, mCtime / 1000.0,
59- mFrames / (mCtime / 1000.0) );
60- mFrames = 0;
61- mCtime = 0;
62+ int dFrames = mFrames - mLastPrintFrames;
63+ mLastPrintFrames = mFrames;
64+ g_print ("[BENCH] : %d frames in %d.%01d seconds = %d.%03d FPS\n",
65+ dFrames, dTime / 1000, (dTime % 1000) / 100,
66+ dFrames * 1000 / dTime, ((dFrames * 1000) % dTime) / 10);
67+ mLastPrint = now;
68 }
69 }
70
71- cScreen->preparePaint ((mAlpha > 0.0) ? timediff : msSinceLastPaint);
72-
73 if (mActive)
74+ {
75 mAlpha += timediff / 1000.0;
76+ if (mAlpha >= 1.0f)
77+ {
78+ mAlpha = 1.0f;
79+ /*
80+ * If we're only creating "fake" damage to update the benchmark
81+ * and no other damage is pending, then do it progressively
82+ * less often so the framerate can steadily decrease toward zero.
83+ */
84+ if (mFakedDamage)
85+ mTimer.setTimes (mTimer.minTime () * 2);
86+ else
87+ {
88+ /*
89+ * Piggyback on damage events other than our own, so the
90+ * benchmark updates at least as often as the rest
91+ * of the screen.
92+ */
93+ damageSelf ();
94+ if (mTimer.minTime () != MIN_MS_PER_UPDATE)
95+ mTimer.setTimes (MIN_MS_PER_UPDATE);
96+ }
97+ }
98+ }
99 else
100 {
101 if (mAlpha <= 0.0)
102 {
103 cScreen->preparePaintSetEnabled (this, false);
104- cScreen->donePaintSetEnabled (this, false);
105 gScreen->glPaintOutputSetEnabled (this, false);
106+ mTimer.stop ();
107 }
108 mAlpha -= timediff / 1000.0;
109+ if (mAlpha < 0.0f)
110+ mAlpha = 0.0f;
111 }
112
113- mAlpha = MIN (1.0, MAX (0.0, mAlpha) );
114+ mFakedDamage = false;
115+
116+ cScreen->preparePaint (msSinceLastPaint);
117 }
118
119-void
120-BenchScreen::donePaint ()
121+float
122+BenchScreen::averageFramerate () const
123+/*
124+ * Returns the average frame rate of the last SECONDS_PER_AVERAGE seconds.
125+ * This calculation is accurate no matter how often/seldom the screen
126+ * gets painted. No timers required. Calculus rocks :)
127+ */
128 {
129- if (mAlpha > 0.0)
130- {
131- cScreen->damageScreen ();
132- glFlush();
133- XSync (::screen->dpy (), false);
134- }
135-
136- cScreen->donePaint ();
137+ const int usPerAverage = SECONDS_PER_AVERAGE * 1000000;
138+ int i = (mFrames + MAX_SAMPLES - 1) % MAX_SAMPLES;
139+ int lastSample = 0;
140+ int timeSum = 0;
141+ int count = 0;
142+ int maxCount = MIN (MAX_SAMPLES, mFrames);
143+
144+ while (timeSum < usPerAverage && count < maxCount)
145+ {
146+ lastSample = mSample[i];
147+ timeSum += lastSample;
148+ i = (i + MAX_SAMPLES - 1) % MAX_SAMPLES;
149+ count++;
150+ }
151+
152+ float fps = 0.0f;
153+ if (timeSum < usPerAverage)
154+ {
155+ if (timeSum > 0)
156+ fps = (float)(count * 1000000) / timeSum;
157+ }
158+ else
159+ {
160+ fps = (float)(count - 1);
161+ if (lastSample > 0)
162+ fps += (float)(usPerAverage - (timeSum - lastSample)) / lastSample;
163+ fps /= SECONDS_PER_AVERAGE;
164+ }
165+
166+ return fps;
167 }
168
169 bool
170@@ -124,7 +171,9 @@
171 glColor4f (1.0, 1.0, 1.0, mAlpha);
172 glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
173
174- glTranslatef (optionGetPositionX (), optionGetPositionY (), 0);
175+ mRect.setX (optionGetPositionX ());
176+ mRect.setY (optionGetPositionY ());
177+ glTranslatef (mRect.x (), mRect.y (), 0);
178
179 glEnable (GL_TEXTURE_2D);
180 glBindTexture (GL_TEXTURE_2D, mBackTex);
181@@ -133,11 +182,11 @@
182 glTexCoord2f (0, 0);
183 glVertex2f (0, 0);
184 glTexCoord2f (0, 1);
185- glVertex2f (0, 256);
186+ glVertex2f (0, TEX_HEIGHT);
187 glTexCoord2f (1, 1);
188- glVertex2f (512, 256);
189+ glVertex2f (TEX_WIDTH, TEX_HEIGHT);
190 glTexCoord2f (1, 0);
191- glVertex2f (512, 0);
192+ glVertex2f (TEX_WIDTH, 0);
193 glEnd();
194
195 glBindTexture (GL_TEXTURE_2D, 0);
196@@ -145,15 +194,24 @@
197
198 glTranslatef (53, 83, 0);
199
200- float rrVal = MIN (1.0, MAX (0.0, mRrVal) );
201+ float avgFps = averageFramerate ();
202+ float rrVal = avgFps * cScreen->optimalRedrawTime () / 1000.0;
203+ /*
204+ * rrVal is slightly inaccurate and can be off by a couple of FPS.
205+ * This means the graph for a 60 FPS config goes up to 62.5 FPS.
206+ * This is because cScreen->optimalRedrawTime only has millisec precision
207+ * and can't be avoided without improving the precision of the composite
208+ * plugin.
209+ */
210+ rrVal = MIN (1.0, MAX (0.0, rrVal) );
211
212 if (rrVal < 0.5)
213 {
214 glBegin (GL_QUADS);
215- glColor4f (1.0, 0.0, 0.0, mAlpha);
216+ glColor4f (0.0, 1.0, 0.0, mAlpha);
217 glVertex2f (0.0, 0.0);
218 glVertex2f (0.0, 25.0);
219- glColor4f (1.0, rrVal * 2.0, 0.0, mAlpha);
220+ glColor4f (rrVal * 2.0, 1.0, 0.0, mAlpha);
221 glVertex2f (330.0 * rrVal, 25.0);
222 glVertex2f (330.0 * rrVal, 0.0);
223 glEnd();
224@@ -161,7 +219,7 @@
225 else
226 {
227 glBegin (GL_QUADS);
228- glColor4f (1.0, 0.0, 0.0, mAlpha);
229+ glColor4f (0.0, 1.0, 0.0, mAlpha);
230 glVertex2f (0.0, 0.0);
231 glVertex2f (0.0, 25.0);
232 glColor4f (1.0, 1.0, 0.0, mAlpha);
233@@ -173,7 +231,7 @@
234 glColor4f (1.0, 1.0, 0.0, mAlpha);
235 glVertex2f (165.0, 0.0);
236 glVertex2f (165.0, 25.0);
237- glColor4f (1.0 - ( (rrVal - 0.5) * 2.0), 1.0, 0.0, mAlpha);
238+ glColor4f (1.0, 1.0 - ( (rrVal - 0.5) * 2.0), 0.0, mAlpha);
239 glVertex2f (165.0 + 330.0 * (rrVal - 0.5), 25.0);
240 glVertex2f (165.0 + 330.0 * (rrVal - 0.5), 0.0);
241 glEnd();
242@@ -182,71 +240,25 @@
243 glColor4f (0.0, 0.0, 0.0, mAlpha);
244 glCallList (mDList);
245 glTranslatef (72, 45, 0);
246-
247- float red;
248-
249- if (mFps > 30.0)
250- red = 0.0;
251- else
252- red = 1.0;
253-
254- if (mFps <= 30.0 && mFps > 20.0)
255- red = 1.0 - ( (mFps - 20.0) / 10.0);
256-
257- glColor4f (red, 0.0, 0.0, mAlpha);
258 glEnable (GL_TEXTURE_2D);
259
260 isSet = false;
261
262- fps = (mFps * 100.0);
263+ fps = (avgFps * 100.0);
264 fps = MIN (999999, fps);
265
266- if (fps >= 100000)
267- {
268- glBindTexture (GL_TEXTURE_2D, mNumTex[fps / 100000]);
269- glCallList (mDList + 1);
270- isSet = true;
271- }
272-
273- fps %= 100000;
274-
275- glTranslatef (12, 0, 0);
276-
277- if (fps >= 10000 || isSet)
278- {
279- glBindTexture (GL_TEXTURE_2D, mNumTex[fps / 10000]);
280- glCallList (mDList + 1);
281- isSet = true;
282- }
283-
284- fps %= 10000;
285-
286- glTranslatef (12, 0, 0);
287-
288- if (fps >= 1000 || isSet)
289- {
290- glBindTexture (GL_TEXTURE_2D, mNumTex[fps / 1000]);
291- glCallList (mDList + 1);
292- }
293-
294- fps %= 1000;
295-
296- glTranslatef (12, 0, 0);
297-
298- glBindTexture (GL_TEXTURE_2D, mNumTex[fps / 100]);
299- glCallList (mDList + 1);
300- fps %= 100;
301-
302- glTranslatef (19, 0, 0);
303-
304- glBindTexture (GL_TEXTURE_2D, mNumTex[fps / 10]);
305- glCallList (mDList + 1);
306- fps %= 10;
307-
308- glTranslatef (12, 0, 0);
309-
310- glBindTexture (GL_TEXTURE_2D, mNumTex[fps]);
311- glCallList (mDList + 1);
312+ for (unsigned int pos = 100000; pos >= 1; pos /= 10)
313+ {
314+ if (fps >= pos || isSet || pos <= 100)
315+ {
316+ unsigned int digit = fps / pos;
317+ glBindTexture (GL_TEXTURE_2D, mNumTex[digit]);
318+ glCallList (mDList + 1);
319+ isSet = true;
320+ fps %= pos;
321+ }
322+ glTranslatef ((pos == 100) ? 19 : 12, 0, 0);
323+ }
324
325 glBindTexture (GL_TEXTURE_2D, 0);
326 glDisable (GL_TEXTURE_2D);
327@@ -275,7 +287,6 @@
328 BenchScreen::postLoad ()
329 {
330 cScreen->preparePaintSetEnabled (this, mActive);
331- cScreen->donePaintSetEnabled (this, mActive);
332 gScreen->glPaintOutputSetEnabled (this, mActive);
333 }
334
335@@ -284,11 +295,10 @@
336 PluginStateWriter <BenchScreen> (this, screen->root ()),
337 cScreen (CompositeScreen::get (screen)),
338 gScreen (GLScreen::get (screen)),
339- mRrVal (0),
340- mFps (0),
341 mAlpha (0),
342- mCtime (0),
343+ mFakedDamage (false),
344 mFrames (0),
345+ mLastPrintFrames (0),
346 mActive (false),
347 mOldLimiterMode ((CompositeFPSLimiterMode)
348 BenchOptions::FpsLimiterModeDefaultLimiter)
349@@ -302,6 +312,10 @@
350 CompositeScreenInterface::setHandler (cScreen, false);
351 GLScreenInterface::setHandler (gScreen, false);
352
353+ mRect.setGeometry (optionGetPositionX (), optionGetPositionY (),
354+ TEX_WIDTH, TEX_HEIGHT);
355+ mTimer.setCallback (boost::bind (&BenchScreen::timedOut, this));
356+
357 glGenTextures (10, mNumTex);
358 glGenTextures (1, &mBackTex);
359
360@@ -333,7 +347,7 @@
361 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
362 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
363
364- glTexImage2D (GL_TEXTURE_2D, 0, 4, 512, 256, 0, GL_RGBA,
365+ glTexImage2D (GL_TEXTURE_2D, 0, 4, TEX_WIDTH, TEX_HEIGHT, 0, GL_RGBA,
366 GL_UNSIGNED_BYTE, image_data);
367 GLERR;
368
369@@ -402,6 +416,21 @@
370 glDeleteTextures (1, &mBackTex);
371 }
372
373+void
374+BenchScreen::damageSelf ()
375+{
376+ CompRegion self (mRect);
377+ cScreen->damageRegion (self);
378+}
379+
380+bool
381+BenchScreen::timedOut ()
382+{
383+ mFakedDamage = (cScreen->damageMask () == 0);
384+ damageSelf ();
385+ return true;
386+}
387+
388 bool
389 BenchScreen::initiate (CompOption::Vector &options)
390 {
391@@ -424,20 +453,24 @@
392 optionGetFpsLimiterMode ());
393
394 cScreen->preparePaintSetEnabled (this, true);
395- cScreen->donePaintSetEnabled (this, true);
396 gScreen->glPaintOutputSetEnabled (this, true);
397+
398+ for (int t = 0; t < MAX_SAMPLES; t++)
399+ mSample[t] = 0;
400 }
401 else
402 {
403 // Restore FPS limiter mode
404 cScreen->setFPSLimiterMode (mOldLimiterMode);
405+ mTimer.stop ();
406 }
407+ mTimer.start (1000 / FADE_FPS);
408
409- cScreen->damageScreen ();
410- mCtime = 0;
411 mFrames = 0;
412+ mLastPrintFrames = 0;
413
414 gettimeofday (&mLastRedraw, 0);
415+ mLastPrint = mLastRedraw;
416
417 return false;
418 }
419
420=== modified file 'src/bench.h'
421--- src/bench.h 2010-07-02 06:30:32 +0000
422+++ src/bench.h 2011-12-05 05:01:23 +0000
423@@ -7,6 +7,9 @@
424 * Copyright : (C) 2006 by Dennis Kasprzyk
425 * E-mail : onestone@beryl-project.org
426 *
427+ * New frame rate measurement algorithm:
428+ * Copyright (c) 2011 Daniel van Vugt <vanvugt@gmail.com>
429+ *
430 *
431 * This program is free software; you can redistribute it and/or
432 * modify it under the terms of the GNU General Public License
433@@ -21,6 +24,7 @@
434 **/
435
436 #include <core/core.h>
437+#include <core/timer.h>
438 #include <core/serialization.h>
439 #include <core/pluginclasshandler.h>
440
441@@ -71,15 +75,27 @@
442 GLScreen *gScreen;
443
444 GLuint mDList;
445- float mRrVal;
446- float mFps;
447 float mAlpha;
448
449+ enum {
450+ MAX_FPS = 500,
451+ FADE_FPS = 50,
452+ SECONDS_PER_AVERAGE = 2,
453+ MAX_SAMPLES = MAX_FPS * SECONDS_PER_AVERAGE,
454+ MIN_MS_PER_UPDATE = 1000
455+ };
456+
457+ bool mFakedDamage;
458+ CompRect mRect;
459+ CompTimer mTimer;
460+
461+ int mSample[MAX_SAMPLES];
462+ int mFrames;
463+ int mLastPrintFrames;
464+
465+ struct timeval mLastPrint;
466 struct timeval mLastRedraw;
467
468- float mCtime;
469- float mFrames;
470-
471 GLuint mNumTex[10];
472 GLuint mBackTex;
473
474@@ -87,6 +103,9 @@
475
476 CompositeFPSLimiterMode mOldLimiterMode;
477
478+ void damageSelf ();
479+ bool timedOut ();
480+ float averageFramerate () const;
481 void postLoad ();
482
483 template <class Archive>
484@@ -100,7 +119,6 @@
485 void limiterModeChanged (CompOption *opt);
486
487 void preparePaint (int msSinceLastPaint);
488- void donePaint ();
489
490 bool glPaintOutput (const GLScreenPaintAttrib &,
491 const GLMatrix &, const CompRegion &,

Subscribers

People subscribed via source and target branches

to all changes: