132001f49Smrg/*
232001f49Smrg * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
332001f49Smrg *
432001f49Smrg * Permission is hereby granted, free of charge, to any person obtaining a
532001f49Smrg * copy of this software and associated documentation files (the "Software"),
632001f49Smrg * to deal in the Software without restriction, including without limitation
732001f49Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
832001f49Smrg * and/or sell copies of the Software, and to permit persons to whom the
932001f49Smrg * Software is furnished to do so, subject to the following conditions:
1032001f49Smrg *
1132001f49Smrg * The above copyright notice and this permission notice shall be included
1232001f49Smrg * in all copies or substantial portions of the Software.
1332001f49Smrg *
1432001f49Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1532001f49Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1632001f49Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1732001f49Smrg * VMWARE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1832001f49Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1932001f49Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2032001f49Smrg */
2132001f49Smrg
2232001f49Smrg/**
2332001f49Smrg * Common perf code.  This should be re-usable with other APIs.
2432001f49Smrg */
2532001f49Smrg
2632001f49Smrg#include "common.h"
2732001f49Smrg#include "glmain.h"
2832001f49Smrg
2932001f49Smrg#include <stdio.h>
3032001f49Smrg#include <stdlib.h>
3132001f49Smrg#include <stdarg.h>
3232001f49Smrg
3332001f49Smrg#if defined(_MSC_VER)
3432001f49Smrg#define snprintf _snprintf
3532001f49Smrg#endif
3632001f49Smrg
3732001f49Smrg
3832001f49Smrg/* Need to add a fflush windows console with mingw, otherwise nothing
3932001f49Smrg * shows up until program exit.  May want to add logging here.
4032001f49Smrg */
4132001f49Smrgvoid
4232001f49Smrgperf_printf(const char *format, ...)
4332001f49Smrg{
4432001f49Smrg   va_list ap;
4532001f49Smrg   va_start(ap, format);
4632001f49Smrg
4732001f49Smrg   fflush(stdout);
4832001f49Smrg   vfprintf(stdout, format, ap);
4932001f49Smrg   fflush(stdout);
5032001f49Smrg
5132001f49Smrg   va_end(ap);
5232001f49Smrg}
5332001f49Smrg
5432001f49Smrg
5532001f49Smrg
5632001f49Smrg/**
5732001f49Smrg * Run function 'f' for enough iterations to reach a steady state.
5832001f49Smrg * Return the rate (iterations/second).
5932001f49Smrg */
6032001f49Smrgdouble
6132001f49SmrgPerfMeasureRate(PerfRateFunc f)
6232001f49Smrg{
6332001f49Smrg   const double minDuration = 1.0;
6432001f49Smrg   double rate = 0.0, prevRate = 0.0;
6532001f49Smrg   unsigned subiters;
6632001f49Smrg
6732001f49Smrg   /* Compute initial number of iterations to try.
6832001f49Smrg    * If the test function is pretty slow this helps to avoid
6932001f49Smrg    * extraordarily long run times.
7032001f49Smrg    */
7132001f49Smrg   subiters = 2;
7232001f49Smrg   {
7332001f49Smrg      const double t0 = PerfGetTime();
7432001f49Smrg      double t1;
7532001f49Smrg      do {
7632001f49Smrg         f(subiters); /* call the rendering function */
7732001f49Smrg         t1 = PerfGetTime();
7832001f49Smrg         subiters *= 2;
7932001f49Smrg      } while (t1 - t0 < 0.1 * minDuration);
8032001f49Smrg   }
8132001f49Smrg   /*perf_printf("initial subIters = %u\n", subiters);*/
8232001f49Smrg
8332001f49Smrg   while (1) {
8432001f49Smrg      const double t0 = PerfGetTime();
8532001f49Smrg      unsigned iters = 0;
8632001f49Smrg      double t1;
8732001f49Smrg
8832001f49Smrg      do {
8932001f49Smrg         f(subiters); /* call the rendering function */
9032001f49Smrg         t1 = PerfGetTime();
9132001f49Smrg         iters += subiters;
9232001f49Smrg      } while (t1 - t0 < minDuration);
9332001f49Smrg
9432001f49Smrg      rate = iters / (t1 - t0);
9532001f49Smrg
9632001f49Smrg      if (0)
9732001f49Smrg         perf_printf("prevRate %f  rate  %f  ratio %f  iters %u\n",
9832001f49Smrg                prevRate, rate, rate/prevRate, iters);
9932001f49Smrg
10032001f49Smrg      /* Try and speed the search up by skipping a few steps:
10132001f49Smrg       */
10232001f49Smrg      if (rate > prevRate * 1.6)
10332001f49Smrg         subiters *= 8;
10432001f49Smrg      else if (rate > prevRate * 1.2)
10532001f49Smrg         subiters *= 4;
10632001f49Smrg      else if (rate > prevRate * 1.05)
10732001f49Smrg         subiters *= 2;
10832001f49Smrg      else
10932001f49Smrg         break;
11032001f49Smrg
11132001f49Smrg      prevRate = rate;
11232001f49Smrg   }
11332001f49Smrg
11432001f49Smrg   if (0)
11532001f49Smrg      perf_printf("%s returning iters %u  rate %f\n", __FUNCTION__, subiters, rate);
11632001f49Smrg   return rate;
11732001f49Smrg}
11832001f49Smrg
11932001f49Smrg
12032001f49Smrg/* Note static buffer, can only use once per printf.
12132001f49Smrg */
12232001f49Smrgconst char *
12332001f49SmrgPerfHumanFloat( double d )
12432001f49Smrg{
12532001f49Smrg   static char buf[80];
12632001f49Smrg
12732001f49Smrg   if (d > 1000000000.0)
12832001f49Smrg      snprintf(buf, sizeof(buf), "%.1f billion", d / 1000000000.0);
12932001f49Smrg   else if (d > 1000000.0)
13032001f49Smrg      snprintf(buf, sizeof(buf), "%.1f million", d / 1000000.0);
13132001f49Smrg   else if (d > 1000.0)
13232001f49Smrg      snprintf(buf, sizeof(buf), "%.1f thousand", d / 1000.0);
13332001f49Smrg   else
13432001f49Smrg      snprintf(buf, sizeof(buf), "%.1f", d);
13532001f49Smrg
13632001f49Smrg   return buf;
13732001f49Smrg}
138