<commit_before>/* -------------------------------------------------------------------------- *
 *                   Simbody(tm): Gazebo Inelastic Collision                  *
 * -------------------------------------------------------------------------- *
 * This is part of the SimTK biosimulation toolkit originating from           *
 * Simbios, the NIH National Center for Physics-Based Simulation of           *
 * Biological Structures at Stanford, funded under the NIH Roadmap for        *
 * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody.  *
 *                                                                            *
 * Portions copyright (c) 2013 Stanford University and the Authors.           *
 * Authors: Michael Sherman                                                   *
 * Contributors:                                                              *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
 * not use this file except in compliance with the License. You may obtain a  *
 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 * -------------------------------------------------------------------------- */

/* This test is drawn from the Open Source Robotics Foundation Gazebo physics
regression test "CollisionTest". In the original test there is a cube and
a sphere, both of unit mass and same half-dimension 0.5. Initially they are 1
unit apart in x, with the block to the left of the sphere. The block is
accelerated to the right with a discrete applied force of 1000 applied for 1ms
for a total impulse of 1, which should produce a velocity of +1 that is steady
until the block hits the stationary sphere. The collision is supposed to be
fully inelastic (coefficient of restitution=0), so there should be no rebound
and the two objects should move off to the right together at half the impact
velocity.

The test runs with fixed 1ms steps and calculates the expected result by
integrating manually. The position and velocity changes during the first step
with the 1000 unit force active are
   x(.001) = 1/2 a t^2 = 1/2 1e3 1e-6 = .0005 length units
   v(.001) = a t       = 1e3 1e-3     = 1 velocity unit
After that first step, all subsequent steps prior to the collision have
   deltaX = v t       = 1 1e-3       = .001 length units
   deltaV = 0
We would like the collision to occur exactly at 1s, that is, between steps 1000
and 1001. The position x(1)=.0005 + 999*.001=.9995. So we'll place the sphere
initially so that the block surface and sphere surface are separated by .9995.

Note that while any integrator can get the velocity correct in one step, no
first order integrator will be able to calculate x(.001) correctly in a single
step.
  Explicit Euler:           v(.001)=v(0) + h*a(0)=1
                            x(.001)=x(0) + h*v(0)=0                 <--

  Semi-explicit Euler:      v(.001)=v(0) + h*a(0)=1
                            x(.001)=x(0) + h*v(.001)=.001.          <--

  Semi-explicit Euler 2:    v'(.0005)=v(0)+h/2 a(0)=.5
                            x'(.0005)=x(0)+h/2 v'(.0005)=.00025
                            v(.001)=v'(.0005)+h/2 a'(.0005)=1
                            x(.001)=x'(.0005)+h/2 v(.001)=.00075    <--

But any 2nd order integrator would give the correct result, for example
Explicit trapezoid rule:    v'(.001)=v(0)+h*a(0)=1
                            x(.001)=x(0)+h*(v(0)+v'(.001))/2 =.0005 <--

Explicit midpoint rule:     v'(.0005)=v(0)+h/2*a(0)=1/2
                            x(.001)=x(0)+h*v'(.0005)=.0005          <--
*/

#include "Simbody.h"

#include <cassert>
#include <iostream>
using std::cout; using std::endl;

using namespace SimTK;

//#define USE_VISUALIZER

// Write interesting integrator info to stdout.
static void dumpIntegratorStats(const Integrator& integ);

const Real Radius = 0.5;
const Real Mass = 1;
// Define an extremely stiff, lossy material.
const Real Stiffness = 1e8;
const Real Dissipation = 1000;

const Real MaxStepSize    = Real(1/1000.); // 1 ms (1000 Hz)
const int  DrawEveryN     = 33;            // 33 ms frame update (30.3 Hz)
const Real SimTime        = 2;
const int  NSteps         = // make this a whole number of viz frames
    DrawEveryN*(int(SimTime/MaxStepSize/DrawEveryN+0.5));

const Real TotalImpulse   = 1; // Applied only on the first step
const Real StepForce      = TotalImpulse/MaxStepSize;

const Real IntegAccuracy = 1e-3;
const Real CheckAccuracy = 1e-3;

struct MyMultibodySystem {
    MyMultibodySystem()
    :   m_system(), m_matter(m_system),
        m_tracker(m_system), m_contact(m_system,m_tracker),
        m_forces(m_system), m_discrete(m_forces,m_matter)
        #ifdef USE_VISUALIZER
        , m_viz(m_system)
        #endif
    {
        ContactMaterial lossyMaterial(Stiffness,
                                      Dissipation,
                                      0,  // mu_static
                                      0,  // mu_dynamic
                                      0); // mu_viscous

        // no gravity
        Body::Rigid sphereBody
           (MassProperties(Mass, Vec3(0), UnitInertia::sphere(Radius)));
        sphereBody.addDecoration(Transform(), DecorativeSphere(Radius));
        sphereBody.addContactSurface(Transform(),
            ContactSurface(ContactGeometry::Sphere(Radius),
                           lossyMaterial));

        // TODO: using inscribed sphere as contact shape within the block.
        Body::Rigid cubeBody
           (MassProperties(Mass, Vec3(0), UnitInertia::sphere(Radius)));
        cubeBody.addDecoration(Transform(), DecorativeBrick(Vec3(Radius)));
        cubeBody.addContactSurface(Transform(),
            ContactSurface(ContactGeometry::Sphere(Radius), // TODO!
                           lossyMaterial));

        MobilizedBody Ground = m_matter.Ground();

        m_cube   = MobilizedBody::Slider(Ground,   Transform(Vec3(0,2,0)),
                                         cubeBody, Transform(Vec3(0)));
        m_sphere = MobilizedBody::Slider(Ground,   Transform(Vec3(2-.0005,2,0)),
                                         sphereBody, Transform(Vec3(0)));

        m_system.realizeTopology();

        #ifdef USE_VISUALIZER
        m_viz.setShowFrameNumber(true);
        m_viz.setShowSimTime(true);
        #endif
    }

    MultibodySystem                 m_system;
    SimbodyMatterSubsystem          m_matter;
    ContactTrackerSubsystem         m_tracker;
    CompliantContactSubsystem       m_contact;
    GeneralForceSubsystem           m_forces;
    Force::DiscreteForces           m_discrete;
    #ifdef USE_VISUALIZER
    Visualizer                      m_viz;
    #endif

    MobilizedBody                   m_cube;
    MobilizedBody                   m_sphere;
};

void runOnce(const MyMultibodySystem& mbs, Integrator& integ)
{
    integ.setAllowInterpolation(false);
    integ.setAccuracy(IntegAccuracy);
    integ.initialize(mbs.m_system.getDefaultState());

    printf("Test with order %d integator %s, Accuracy=%g, MaxStepSize=%g\n",
        integ.getMethodMinOrder(), integ.getMethodName(),
        integ.getAccuracyInUse(), MaxStepSize);

    // These variables are the manually calculated values for the cube's
    // x coordinate and x velocity in Ground. We'll calculate these assuming
    // a perfect inelastic collision occurring at t=1 and then compare with
    // the approximate solution produced by the integrator.
    Real x=0, v=0;

    unsigned stepNum = 0;
    while (true) {
        // Get access to State being advanced by the integrator. Interpolation
        // must be off so that we're modifying the actual trajectory.
        State& state = integ.updAdvancedState();

        #ifdef USE_VISUALIZER
        // Output a frame to the Visualizer if it is time.
        if (stepNum % DrawEveryN == 0)
            mbs.m_viz.report(state);
        #endif

        if (stepNum == NSteps)
            break;

        ++stepNum;

        mbs.m_discrete.clearAllBodyForces(state);
        if (stepNum == 1)
            mbs.m_discrete.setOneBodyForce(state, mbs.m_cube,
                SpatialVec(Vec3(0), Vec3(StepForce,0,0)));

        // Advance time by MaxStepSize. Might take multiple internal steps to
        // get there, depending on difficulty and required accuracy.
        const Real tNext = stepNum * MaxStepSize;
        do {integ.stepTo(tNext,tNext);} while (integ.getTime() < tNext);

        // From Gazebo test code in physics.cc:
        // integrate here to see when the collision should happen
        if (stepNum == 1) {
            const Real a = StepForce/Mass;      // a is acceleration
            v += a * MaxStepSize;               // dv = a t
            x += a * square(MaxStepSize)/2;     // dx = 1/2 a t^2
            if (integ.getMethodMinOrder() == 1) {
                // 1st order method can't get this right
                const Real prevPos = mbs.m_cube.getOneQ(state,MobilizerQIndex(0));
                mbs.m_cube.setOneQ(state, MobilizerQIndex(0), x);
                printf("-------- FIRST ORDER INTEGRATION METHOD --------\n");
                printf("Cube position repaired: was=%g, now=%g\n", prevPos, x);
                printf("------------------------------------------------\n");
                mbs.m_system.realize(state, Stage::Velocity);
            }
        } else {
            const Real impulse = StepForce*MaxStepSize;
            if (stepNum > 1000)
                v = impulse / (2*Mass);  //inelastic col. w/equal mass
            x += v * MaxStepSize;
        }

        SimTK_TEST_EQ_TOL(mbs.m_cube.getBodyOriginLocation(state)[0], x, CheckAccuracy);
        SimTK_TEST_EQ_TOL(mbs.m_cube.getBodyOriginVelocity(state)[0], v, CheckAccuracy);

        //mbs.m_system.realize(state);
        //printf("after step %d t=%g (h=%g): px=%g,%g vx=%g,%g ax=%g,%g\n",
        //    stepNum, state.getTime(),integ.getPreviousStepSizeTaken(),
        //    mbs.m_cube.getBodyOriginLocation(state)[0],
        //    mbs.m_sphere.getBodyOriginLocation(state)[0],
        //    mbs.m_cube.getBodyOriginVelocity(state)[0],
        //    mbs.m_sphere.getBodyOriginVelocity(state)[0],
        //    mbs.m_cube.getBodyOriginAcceleration(state)[0],
        //    mbs.m_sphere.getBodyOriginAcceleration(state)[0]);
        //printf("  x=%g v=%g\n", x, v);
    }

    dumpIntegratorStats(integ);
}

int main() {
    SimTK_START_TEST("GazeboInelasticCollision");
        // Create the system.
        MyMultibodySystem mbs;

        RungeKuttaMersonIntegrator rkm(mbs.m_system);
        RungeKutta3Integrator rk3(mbs.m_system);
        RungeKutta2Integrator rk2(mbs.m_system);
        SemiExplicitEuler2Integrator sexpeul2(mbs.m_system);
        ExplicitEulerIntegrator expeul(mbs.m_system);
        RungeKuttaFeldbergIntegrator rkf(mbs.m_system);
        VerletIntegrator verlet(mbs.m_system);

        SimTK_SUBTEST2(runOnce, mbs, rkm);
        SimTK_SUBTEST2(runOnce, mbs, rk3);
        SimTK_SUBTEST2(runOnce, mbs, rk2);
        SimTK_SUBTEST2(runOnce, mbs, sexpeul2);
        SimTK_SUBTEST2(runOnce, mbs, expeul);

        //sherm 130617: these aren't accurate enough
        //SimTK_SUBTEST2(runOnce, mbs, rkf);
        //SimTK_SUBTEST2(runOnce, mbs, verlet);

    SimTK_END_TEST();
}

//==============================================================================
//                        DUMP INTEGRATOR STATS
//==============================================================================
static void dumpIntegratorStats(const Integrator& integ) {
    const int evals = integ.getNumRealizations();
    std::cout << "\nDone -- simulated " << integ.getTime() << "s with "
            << integ.getNumStepsTaken() << " steps, avg step="
        << (1000*integ.getTime())/integ.getNumStepsTaken() << "ms "
        << (1000*integ.getTime())/evals << "ms/eval\n";

    printf("Used Integrator %s at accuracy %g:\n",
        integ.getMethodName(), integ.getAccuracyInUse());
    printf("# STEPS/ATTEMPTS = %d/%d\n",  integ.getNumStepsTaken(),
                                          integ.getNumStepsAttempted());
    printf("# ERR TEST FAILS = %d\n",     integ.getNumErrorTestFailures());
    printf("# REALIZE/PROJECT = %d/%d\n", integ.getNumRealizations(),
                                          integ.getNumProjections());
}
<commit_msg>Fixed inelastic collision regression test to be more robust when used with first-order integrators. Now the initial impulse is spread over several steps to reduce the amount of error inevitably introduced by those methods.<commit_after>/* -------------------------------------------------------------------------- *
 *                   Simbody(tm): Gazebo Inelastic Collision                  *
 * -------------------------------------------------------------------------- *
 * This is part of the SimTK biosimulation toolkit originating from           *
 * Simbios, the NIH National Center for Physics-Based Simulation of           *
 * Biological Structures at Stanford, funded under the NIH Roadmap for        *
 * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody.  *
 *                                                                            *
 * Portions copyright (c) 2013 Stanford University and the Authors.           *
 * Authors: Michael Sherman                                                   *
 * Contributors:                                                              *
 *                                                                            *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
 * not use this file except in compliance with the License. You may obtain a  *
 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
 *                                                                            *
 * Unless required by applicable law or agreed to in writing, software        *
 * distributed under the License is distributed on an "AS IS" BASIS,          *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
 * See the License for the specific language governing permissions and        *
 * limitations under the License.                                             *
 * -------------------------------------------------------------------------- */

/* This test is drawn from the Open Source Robotics Foundation Gazebo physics
regression test "CollisionTest". In the original test there is a cube and
a sphere, both of unit mass and same half-dimension 0.5. Initially they are 1
unit apart in x, with the block to the left of the sphere. The block is
accelerated to the right with a discrete applied force of 1000 applied for 1ms
for a total impulse of 1, which should produce a velocity of +1 that is steady
until the block hits the stationary sphere. The collision is supposed to be
fully inelastic (coefficient of restitution=0), so there should be no rebound
and the two objects should move off to the right together at half the impact
velocity.

The test runs with fixed 1ms steps and calculates the expected result by
integrating manually. The position and velocity changes during the first step
with the 1000 unit force active are
   x(.001) = 1/2 a t^2 = 1/2 1e3 1e-6 = .0005 length units
   v(.001) = a t       = 1e3 1e-3     = 1 velocity unit
After that first step, all subsequent steps prior to the collision have
   deltaX = v t       = 1 1e-3       = .001 length units
   deltaV = 0
We would like the collision to occur exactly at 1s, that is, between steps 1000
and 1001. The position x(1)=.0005 + 999*.001=.9995. So if we were going to apply
the entire impulse during the first step we would place the sphere initially so
that the block surface and sphere surface are separated by .9995. But read on.

NOTE: to avoid problems with first-order integrators (explanation below), we're
modifying the test here to apply 1/10th of the impulse over the first 10 steps
(.01 seconds) rather than all in the first step. Then
   x(.01) = 1/2 a t^2 = 1/2 1e2 1e-4 = .005 length units
   v(.01) = a t       = 1e2 1e-2     = 1 velocity unit
At 1s we'll have x(1)=.005 + 990*.001=.995. So we'll set the initial separation
to .995 to get a collision at 1s (between steps 1000 and 1001).

Why first order integrators cause trouble
-----------------------------------------
While any integrator can get the velocity correct in one step, no first order
integrator will be able to calculate x(.001) correctly in a single step.
  Explicit Euler:           v(.001)=v(0) + h*a(0)=1
                            x(.001)=x(0) + h*v(0)=0                 <--

  Semi-explicit Euler:      v(.001)=v(0) + h*a(0)=1
                            x(.001)=x(0) + h*v(.001)=.001.          <--

  Semi-explicit Euler 2:    v'(.0005)=v(0)+h/2 a(0)=.5
                            x'(.0005)=x(0)+h/2 v'(.0005)=.00025
                            v(.001)=v'(.0005)+h/2 a'(.0005)=1
                            x(.001)=x'(.0005)+h/2 v(.001)=.00075    <--

But any 2nd order integrator would give the correct result, for example
Explicit trapezoid rule:    v'(.001)=v(0)+h*a(0)=1
                            x(.001)=x(0)+h*(v(0)+v'(.001))/2 =.0005 <--

Explicit midpoint rule:     v'(.0005)=v(0)+h/2*a(0)=1/2
                            x(.001)=x(0)+h*v'(.0005)=.0005          <--

By spreading the impulse over several steps we substantially reduce the overall
error. For example, after ten steps we get
  ExplicitEuler:         x(.01)=.0045
  Semi-explicit Euler:   x(.01)=.0055
  Semi-explicit Euler 2: x(.01)=.00525
any of which we'll deem close enough to the right answer of .005.
*/

#include "Simbody.h"

#include <cassert>
#include <iostream>
using std::cout; using std::endl;

using namespace SimTK;

//#define USE_VISUALIZER

// Write interesting integrator info to stdout.
static void dumpIntegratorStats(const Integrator& integ);

const Real Radius = 0.5;
const Real Mass = 1;
// Define an extremely stiff, lossy material.
const Real Stiffness = 1e8;
const Real Dissipation = 1000;

const Real MaxStepSize    = Real(1/1000.); // 1 ms (1000 Hz)
const int  DrawEveryN     = 33;            // 33 ms frame update (30.3 Hz)
const Real SimTime        = 2;
const int  NSteps         = // make this a whole number of viz frames
    DrawEveryN*(int(SimTime/MaxStepSize/DrawEveryN+0.5));

const Real TotalImpulse   = 1; // Applied only on the first step
const Real StepForce      = TotalImpulse/MaxStepSize;

const Real IntegAccuracy = 1e-3;
const Real CheckAccuracy = 1e-3;

struct MyMultibodySystem {
    MyMultibodySystem()
    :   m_system(), m_matter(m_system),
        m_tracker(m_system), m_contact(m_system,m_tracker),
        m_forces(m_system), m_discrete(m_forces,m_matter)
        #ifdef USE_VISUALIZER
        , m_viz(m_system)
        #endif
    {
        ContactMaterial lossyMaterial(Stiffness,
                                      Dissipation,
                                      0,  // mu_static
                                      0,  // mu_dynamic
                                      0); // mu_viscous

        // no gravity
        Body::Rigid sphereBody
           (MassProperties(Mass, Vec3(0), UnitInertia::sphere(Radius)));
        sphereBody.addDecoration(Transform(), DecorativeSphere(Radius));
        sphereBody.addContactSurface(Transform(),
            ContactSurface(ContactGeometry::Sphere(Radius),
                           lossyMaterial));

        // TODO: using inscribed sphere as contact shape within the block.
        Body::Rigid cubeBody
           (MassProperties(Mass, Vec3(0), UnitInertia::sphere(Radius)));
        cubeBody.addDecoration(Transform(), DecorativeBrick(Vec3(Radius)));
        cubeBody.addContactSurface(Transform(),
            ContactSurface(ContactGeometry::Sphere(Radius), // TODO!
                           lossyMaterial));

        MobilizedBody Ground = m_matter.Ground();

        m_cube   = MobilizedBody::Slider(Ground,   Transform(Vec3(0,2,0)),
                                         cubeBody, Transform(Vec3(0)));
        m_sphere = MobilizedBody::Slider(Ground,   Transform(Vec3(2-.005,2,0)),
                                         sphereBody, Transform(Vec3(0)));

        m_system.realizeTopology();

        #ifdef USE_VISUALIZER
        m_viz.setShowFrameNumber(true);
        m_viz.setShowSimTime(true);
        #endif
    }

    MultibodySystem                 m_system;
    SimbodyMatterSubsystem          m_matter;
    ContactTrackerSubsystem         m_tracker;
    CompliantContactSubsystem       m_contact;
    GeneralForceSubsystem           m_forces;
    Force::DiscreteForces           m_discrete;
    #ifdef USE_VISUALIZER
    Visualizer                      m_viz;
    #endif

    MobilizedBody                   m_cube;
    MobilizedBody                   m_sphere;
};

void runOnce(const MyMultibodySystem& mbs, Integrator& integ, int nsteps)
{
    integ.setAllowInterpolation(false);
    integ.setAccuracy(IntegAccuracy);
    integ.initialize(mbs.m_system.getDefaultState());

    printf(
    "\n--------------------------------------------------------------------\n");
    printf(
    "Test with order %d integator %s, Accuracy=%g, MaxStepSize=%g #steps=%d\n",
        integ.getMethodMinOrder(), integ.getMethodName(),
        integ.getAccuracyInUse(), MaxStepSize, nsteps);

    // These variables are the manually calculated values for the cube's
    // x coordinate and x velocity in Ground. We'll calculate these assuming
    // a perfect inelastic collision occurring at t=1 and then compare with
    // the approximate solution produced by the integrator.
    Real x=0, v=0;

    unsigned stepNum = 0;
    while (true) {
        // Get access to State being advanced by the integrator. Interpolation
        // must be off so that we're modifying the actual trajectory.
        State& state = integ.updAdvancedState();

        #ifdef USE_VISUALIZER
        // Output a frame to the Visualizer if it is time.
        if (stepNum % DrawEveryN == 0)
            mbs.m_viz.report(state);
        #endif

        if (stepNum == nsteps)
            break;

        ++stepNum;

        mbs.m_discrete.clearAllBodyForces(state);
        if (stepNum <= 10)
            mbs.m_discrete.setOneBodyForce(state, mbs.m_cube,
                SpatialVec(Vec3(0), Vec3(StepForce/10,0,0)));

        // Advance time by MaxStepSize. Might take multiple internal steps to
        // get there, depending on difficulty and required accuracy.
        const Real tNext = stepNum * MaxStepSize;
        do {integ.stepTo(tNext,tNext);} while (integ.getTime() < tNext);

        // From Gazebo test code in physics.cc:
        // integrate here to see when the collision should happen
        if (stepNum <= 10) {
            const Real a = StepForce/10/Mass;  // a is acceleration
            x += v*MaxStepSize + a * square(MaxStepSize)/2; // dx = 1/2 a t^2
            v += a * MaxStepSize;                           // dv = a t
        } else {
            const Real impulse = StepForce*MaxStepSize;
            if (stepNum >= 1000)
                v = impulse / (2*Mass);  //inelastic col. w/equal mass
            x += v * MaxStepSize;
        }

        mbs.m_system.realize(state);
        //printf("after step %d t=%g (h=%g): px=%g,%g vx=%g,%g ax=%g,%g\n",
        //    stepNum, state.getTime(),integ.getPreviousStepSizeTaken(),
        //    mbs.m_cube.getBodyOriginLocation(state)[0],
        //    mbs.m_sphere.getBodyOriginLocation(state)[0],
        //    mbs.m_cube.getBodyOriginVelocity(state)[0],
        //    mbs.m_sphere.getBodyOriginVelocity(state)[0],
        //    mbs.m_cube.getBodyOriginAcceleration(state)[0],
        //    mbs.m_sphere.getBodyOriginAcceleration(state)[0]);
        //printf("  x=%g v=%g\n", x, v);

        // Allow some uncertainty between step 1000 and 1001.
        if (stepNum != 1000) {
        SimTK_TEST_EQ_TOL(mbs.m_cube.getBodyOriginLocation(state)[0], x,
                          CheckAccuracy);
        SimTK_TEST_EQ_TOL(mbs.m_cube.getBodyOriginVelocity(state)[0], v,
                          CheckAccuracy);
        }

    }

    dumpIntegratorStats(integ);
}

int main() {
    SimTK_START_TEST("GazeboInelasticCollision");
        // Create the system.
        MyMultibodySystem mbs;

        RungeKuttaMersonIntegrator rkm(mbs.m_system);
        RungeKutta3Integrator rk3(mbs.m_system);
        RungeKutta2Integrator rk2(mbs.m_system);
        SemiExplicitEuler2Integrator sexpeul2(mbs.m_system);
        ExplicitEulerIntegrator expeul(mbs.m_system);

        // Fixed step integrators can't adjust to the compliant impact needs.
        SemiExplicitEulerIntegrator sexpeul1(mbs.m_system, MaxStepSize);
        ExplicitEulerIntegrator expeulFixed(mbs.m_system, MaxStepSize);

        SimTK_SUBTEST3(runOnce, mbs, rkm, NSteps);
        SimTK_SUBTEST3(runOnce, mbs, rk3, NSteps);
        SimTK_SUBTEST3(runOnce, mbs, rk2, NSteps);
        SimTK_SUBTEST3(runOnce, mbs, sexpeul2, NSteps);
        SimTK_SUBTEST3(runOnce, mbs, expeul, NSteps);

        // These are fixed-step integrators so can't handle the
        // compliant impact which demands a few smaller steps for stability
        SimTK_SUBTEST3(runOnce, mbs, sexpeul1, 990); // stop before impact
        SimTK_SUBTEST3(runOnce, mbs, expeulFixed, 990);

        //sherm 130617: this isn't accurate enough; I think it has a serious
        // bug in its error estimator
        //VerletIntegrator verlet(mbs.m_system);
        //SimTK_SUBTEST2(runOnce, mbs, verlet);

        //this has poor accuracy control also
        //RungeKuttaFeldbergIntegrator rkf(mbs.m_system);
        //SimTK_SUBTEST3(runOnce, mbs, rkf, NSteps);

    SimTK_END_TEST();
}

//==============================================================================
//                        DUMP INTEGRATOR STATS
//==============================================================================
static void dumpIntegratorStats(const Integrator& integ) {
    const int evals = integ.getNumRealizations();
    std::cout << "\nDone -- simulated " << integ.getTime() << "s with "
            << integ.getNumStepsTaken() << " steps, avg step="
        << (1000*integ.getTime())/integ.getNumStepsTaken() << "ms "
        << (1000*integ.getTime())/evals << "ms/eval\n";

    printf("Used Integrator %s at accuracy %g:\n",
        integ.getMethodName(), integ.getAccuracyInUse());
    printf("# STEPS/ATTEMPTS = %d/%d\n",  integ.getNumStepsTaken(),
                                          integ.getNumStepsAttempted());
    printf("# ERR TEST FAILS = %d\n",     integ.getNumErrorTestFailures());
    printf("# REALIZE/PROJECT = %d/%d\n", integ.getNumRealizations(),
                                          integ.getNumProjections());
}
<|endoftext|>


<commit_before><commit_msg>Fixed configload status being casted to bool.<commit_after><|endoftext|>


<commit_before><commit_msg>Included implementation file to GameOverState.<commit_after><|endoftext|>


<commit_before>//
// Copyright (c) 2008-2014 the Urho3D project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "Precompiled.h"
#include "AttributeAnimation.h"
#include "XMLFile.h"

#include "DebugNew.h"

namespace Urho3D
{

AttributeAnimation::AttributeAnimation(Context* context) :
    Resource(context),
    cycleMode_(CM_LOOP),
    valueType_(VAR_NONE),
    beginTime_(M_INFINITY),
    endTime_(-M_INFINITY)
{
}

AttributeAnimation::~AttributeAnimation()
{
}

void AttributeAnimation::RegisterObject(Context* context)
{
    context->RegisterFactory<AttributeAnimation>();
}

bool AttributeAnimation::Load(Deserializer& source)
{
    XMLFile xmlFile(context_);
    if (xmlFile.Load(source))
        return false;

    XMLElement rootElem = xmlFile.GetRoot("AttributeAnimation");
    if (!rootElem)
        return false;

    return LoadXML(rootElem);
}

bool AttributeAnimation::Save(Serializer& dest) const
{
    XMLFile xmlFile(context_);

    XMLElement rootElem = xmlFile.CreateRoot("AttributeAnimation");
    if (!SaveXML(rootElem))
        return false;

    return xmlFile.Save(dest);
}

bool AttributeAnimation::LoadXML(const XMLElement& source)
{
    if (source.GetName() != "AttributeAnimation")
        return false;

    keyframes_.Clear();

    cycleMode_ = (CycleMode)source.GetInt("cycle mode");
    valueType_ = (VariantType)source.GetInt("value type");

    XMLElement keyFrameEleme = source.GetChild("KeyFrame");
    while (keyFrameEleme)
    {
        float time = keyFrameEleme.GetFloat("time");
        Variant value(valueType_, keyFrameEleme.GetAttribute("value"));
        SetKeyFrame(time, value);

        keyFrameEleme = keyFrameEleme.GetNext("KeyFrame");
    }

    return true;
}

bool AttributeAnimation::SaveXML(XMLElement& dest) const
{
    if (dest.GetName() != "AttributeAnimation")
        return false;

    dest.SetInt("cycle mode", (int)cycleMode_);
    dest.SetInt("value type", (int)valueType_);

    for (unsigned i = 0; i < keyframes_.Size(); ++i)
    {
        const KeyFrame& keyFrame = keyframes_[i];
        XMLElement keyFrameEleme = dest.CreateChild("KeyFrame");
        keyFrameEleme.SetFloat("time", keyFrame.time_);
        keyFrameEleme.SetAttribute("value", keyFrame.value_.ToString());
    }

    return true;
}

void AttributeAnimation::SetCycleMode(CycleMode cycleMode)
{
    cycleMode_ = cycleMode;
}

void AttributeAnimation::SetValueType(VariantType valueType)
{
    if (valueType == valueType_)
        return;

    valueType_ = valueType;

    keyframes_.Clear();
    beginTime_ = M_INFINITY;
    endTime_ = -M_INFINITY;
}

bool AttributeAnimation::SetKeyFrame(float time, const Variant& value)
{
    if (valueType_ == VAR_NONE)
        valueType_ = value.GetType();
    else if (value.GetType() != valueType_)
        return false;

    beginTime_ = Min(time, beginTime_);
    endTime_ = Max(time, endTime_);

    KeyFrame keyFrame;
    keyFrame.time_ = time;
    keyFrame.value_ = value;

    if (keyframes_.Empty() || time >= keyframes_.Back().time_)
        keyframes_.Push(keyFrame);
    else
    {
        for (unsigned i = 0; i < keyframes_.Size(); ++i)
        {
            if (time < keyframes_[i].time_)
            {
                keyframes_.Insert(i, keyFrame);
                break;
            }
        }
    }

    return true;
}

void AttributeAnimation::GetAnimationValue(float time, Variant& value) const
{
    if (keyframes_.Empty())
        return;

    float scaledTime = CalculateScaledTime(time);

    for (unsigned i = 1; i < keyframes_.Size(); ++i)
    {
        if (keyframes_[i].time_ > scaledTime)
        {
            Interpolation(keyframes_[i - 1], keyframes_[i], scaledTime, value);
            break;
        }
    }
}

float AttributeAnimation::CalculateScaledTime(float time) const
{
    switch (cycleMode_)
    {
    case CM_LOOP:
        {
            float span = endTime_ - beginTime_;
            return beginTime_ + fmodf(time - beginTime_, span);
        }

    case CM_CLAMP:
        return Clamp(time, beginTime_, endTime_);

    case CM_PINGPONG:
        {
            float span = endTime_ - beginTime_;
            float doubleSpan = span * 2.0f;
            float fract = fmodf(time - beginTime_, doubleSpan);
            return (fract < span) ? beginTime_ + fract : beginTime_ + doubleSpan - fract;
        }
        break;
    }

    return time;
}

void AttributeAnimation::Interpolation(const KeyFrame& loKeyFrame, const KeyFrame& hiKeyFrame, float scaledTime, Variant& value) const
{
    switch (valueType_)
    {
    case VAR_INT:
        value = loKeyFrame.value_.GetInt();
        return;
    case VAR_BOOL:
        value = loKeyFrame.value_.GetBool();
        return;
    case VAR_FLOAT:
        {
            float factor = (scaledTime - loKeyFrame.time_) / (hiKeyFrame.time_ - loKeyFrame.time_);
            value = Lerp(loKeyFrame.value_.GetFloat(), hiKeyFrame.value_.GetFloat(), factor);
        }
        return;
    case VAR_VECTOR2:
        {
            float factor = (scaledTime - loKeyFrame.time_) / (hiKeyFrame.time_ - loKeyFrame.time_);
            value = loKeyFrame.value_.GetVector2().Lerp(hiKeyFrame.value_.GetVector2(), factor);
        }
        return;
    case VAR_VECTOR3:
        {
            float factor = (scaledTime - loKeyFrame.time_) / (hiKeyFrame.time_ - loKeyFrame.time_);
            value = loKeyFrame.value_.GetVector3().Lerp(hiKeyFrame.value_.GetVector3(), factor);
        }
        return;
    case VAR_VECTOR4:
        {
            float factor = (scaledTime - loKeyFrame.time_) / (hiKeyFrame.time_ - loKeyFrame.time_);
            value = loKeyFrame.value_.GetVector4().Lerp(hiKeyFrame.value_.GetVector4(), factor);
        }
        return;
    case VAR_QUATERNION:
        {
            float factor = (scaledTime - loKeyFrame.time_) / (hiKeyFrame.time_ - loKeyFrame.time_);
            value = loKeyFrame.value_.GetQuaternion().Slerp(hiKeyFrame.value_.GetQuaternion(), factor);
        }
        return;
    case VAR_COLOR:
        {
            float factor = (scaledTime - loKeyFrame.time_) / (hiKeyFrame.time_ - loKeyFrame.time_);
            value = loKeyFrame.value_.GetColor().Lerp(hiKeyFrame.value_.GetColor(), factor);
        }
        return;
    case VAR_STRING:
        value = loKeyFrame.value_.GetString();
        return;
    case VAR_BUFFER:
        value = loKeyFrame.value_.GetBuffer();
        return;
    case VAR_VOIDPTR:
        value = loKeyFrame.value_.GetVoidPtr();
        return;
    case VAR_RESOURCEREF:
        value = loKeyFrame.value_.GetResourceRef();
        return;
    case VAR_RESOURCEREFLIST:
        value = loKeyFrame.value_.GetResourceRefList();
        return;
    case VAR_VARIANTVECTOR:
        value = loKeyFrame.value_.GetVariantVector();
        return;
    case VAR_VARIANTMAP:
        value = loKeyFrame.value_.GetVariantMap();
        return;
    case VAR_INTRECT:
        value = loKeyFrame.value_.GetIntRect();
        return;
    case VAR_INTVECTOR2:
        value = loKeyFrame.value_.GetIntVector2();
        return;
    case VAR_PTR:
        value = loKeyFrame.value_.GetPtr();
        return;
    }
}

}
<commit_msg>Add missing header file.<commit_after>//
// Copyright (c) 2008-2014 the Urho3D project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "Precompiled.h"
#include "Context.h"
#include "AttributeAnimation.h"
#include "XMLFile.h"

#include "DebugNew.h"

namespace Urho3D
{

AttributeAnimation::AttributeAnimation(Context* context) :
    Resource(context),
    cycleMode_(CM_LOOP),
    valueType_(VAR_NONE),
    beginTime_(M_INFINITY),
    endTime_(-M_INFINITY)
{
}

AttributeAnimation::~AttributeAnimation()
{
}

void AttributeAnimation::RegisterObject(Context* context)
{
    context->RegisterFactory<AttributeAnimation>();
}

bool AttributeAnimation::Load(Deserializer& source)
{
    XMLFile xmlFile(context_);
    if (xmlFile.Load(source))
        return false;

    XMLElement rootElem = xmlFile.GetRoot("AttributeAnimation");
    if (!rootElem)
        return false;

    return LoadXML(rootElem);
}

bool AttributeAnimation::Save(Serializer& dest) const
{
    XMLFile xmlFile(context_);

    XMLElement rootElem = xmlFile.CreateRoot("AttributeAnimation");
    if (!SaveXML(rootElem))
        return false;

    return xmlFile.Save(dest);
}

bool AttributeAnimation::LoadXML(const XMLElement& source)
{
    if (source.GetName() != "AttributeAnimation")
        return false;

    keyframes_.Clear();

    cycleMode_ = (CycleMode)source.GetInt("cycle mode");
    valueType_ = (VariantType)source.GetInt("value type");

    XMLElement keyFrameEleme = source.GetChild("KeyFrame");
    while (keyFrameEleme)
    {
        float time = keyFrameEleme.GetFloat("time");
        Variant value(valueType_, keyFrameEleme.GetAttribute("value"));
        SetKeyFrame(time, value);

        keyFrameEleme = keyFrameEleme.GetNext("KeyFrame");
    }

    return true;
}

bool AttributeAnimation::SaveXML(XMLElement& dest) const
{
    if (dest.GetName() != "AttributeAnimation")
        return false;

    dest.SetInt("cycle mode", (int)cycleMode_);
    dest.SetInt("value type", (int)valueType_);

    for (unsigned i = 0; i < keyframes_.Size(); ++i)
    {
        const KeyFrame& keyFrame = keyframes_[i];
        XMLElement keyFrameEleme = dest.CreateChild("KeyFrame");
        keyFrameEleme.SetFloat("time", keyFrame.time_);
        keyFrameEleme.SetAttribute("value", keyFrame.value_.ToString());
    }

    return true;
}

void AttributeAnimation::SetCycleMode(CycleMode cycleMode)
{
    cycleMode_ = cycleMode;
}

void AttributeAnimation::SetValueType(VariantType valueType)
{
    if (valueType == valueType_)
        return;

    valueType_ = valueType;

    keyframes_.Clear();
    beginTime_ = M_INFINITY;
    endTime_ = -M_INFINITY;
}

bool AttributeAnimation::SetKeyFrame(float time, const Variant& value)
{
    if (valueType_ == VAR_NONE)
        valueType_ = value.GetType();
    else if (value.GetType() != valueType_)
        return false;

    beginTime_ = Min(time, beginTime_);
    endTime_ = Max(time, endTime_);

    KeyFrame keyFrame;
    keyFrame.time_ = time;
    keyFrame.value_ = value;

    if (keyframes_.Empty() || time >= keyframes_.Back().time_)
        keyframes_.Push(keyFrame);
    else
    {
        for (unsigned i = 0; i < keyframes_.Size(); ++i)
        {
            if (time < keyframes_[i].time_)
            {
                keyframes_.Insert(i, keyFrame);
                break;
            }
        }
    }

    return true;
}

void AttributeAnimation::GetAnimationValue(float time, Variant& value) const
{
    if (keyframes_.Empty())
        return;

    float scaledTime = CalculateScaledTime(time);

    for (unsigned i = 1; i < keyframes_.Size(); ++i)
    {
        if (keyframes_[i].time_ > scaledTime)
        {
            Interpolation(keyframes_[i - 1], keyframes_[i], scaledTime, value);
            break;
        }
    }
}

float AttributeAnimation::CalculateScaledTime(float time) const
{
    switch (cycleMode_)
    {
    case CM_LOOP:
        {
            float span = endTime_ - beginTime_;
            return beginTime_ + fmodf(time - beginTime_, span);
        }

    case CM_CLAMP:
        return Clamp(time, beginTime_, endTime_);

    case CM_PINGPONG:
        {
            float span = endTime_ - beginTime_;
            float doubleSpan = span * 2.0f;
            float fract = fmodf(time - beginTime_, doubleSpan);
            return (fract < span) ? beginTime_ + fract : beginTime_ + doubleSpan - fract;
        }
        break;
    }

    return time;
}

void AttributeAnimation::Interpolation(const KeyFrame& loKeyFrame, const KeyFrame& hiKeyFrame, float scaledTime, Variant& value) const
{
    switch (valueType_)
    {
    case VAR_INT:
        value = loKeyFrame.value_.GetInt();
        return;
    case VAR_BOOL:
        value = loKeyFrame.value_.GetBool();
        return;
    case VAR_FLOAT:
        {
            float factor = (scaledTime - loKeyFrame.time_) / (hiKeyFrame.time_ - loKeyFrame.time_);
            value = Lerp(loKeyFrame.value_.GetFloat(), hiKeyFrame.value_.GetFloat(), factor);
        }
        return;
    case VAR_VECTOR2:
        {
            float factor = (scaledTime - loKeyFrame.time_) / (hiKeyFrame.time_ - loKeyFrame.time_);
            value = loKeyFrame.value_.GetVector2().Lerp(hiKeyFrame.value_.GetVector2(), factor);
        }
        return;
    case VAR_VECTOR3:
        {
            float factor = (scaledTime - loKeyFrame.time_) / (hiKeyFrame.time_ - loKeyFrame.time_);
            value = loKeyFrame.value_.GetVector3().Lerp(hiKeyFrame.value_.GetVector3(), factor);
        }
        return;
    case VAR_VECTOR4:
        {
            float factor = (scaledTime - loKeyFrame.time_) / (hiKeyFrame.time_ - loKeyFrame.time_);
            value = loKeyFrame.value_.GetVector4().Lerp(hiKeyFrame.value_.GetVector4(), factor);
        }
        return;
    case VAR_QUATERNION:
        {
            float factor = (scaledTime - loKeyFrame.time_) / (hiKeyFrame.time_ - loKeyFrame.time_);
            value = loKeyFrame.value_.GetQuaternion().Slerp(hiKeyFrame.value_.GetQuaternion(), factor);
        }
        return;
    case VAR_COLOR:
        {
            float factor = (scaledTime - loKeyFrame.time_) / (hiKeyFrame.time_ - loKeyFrame.time_);
            value = loKeyFrame.value_.GetColor().Lerp(hiKeyFrame.value_.GetColor(), factor);
        }
        return;
    case VAR_STRING:
        value = loKeyFrame.value_.GetString();
        return;
    case VAR_BUFFER:
        value = loKeyFrame.value_.GetBuffer();
        return;
    case VAR_VOIDPTR:
        value = loKeyFrame.value_.GetVoidPtr();
        return;
    case VAR_RESOURCEREF:
        value = loKeyFrame.value_.GetResourceRef();
        return;
    case VAR_RESOURCEREFLIST:
        value = loKeyFrame.value_.GetResourceRefList();
        return;
    case VAR_VARIANTVECTOR:
        value = loKeyFrame.value_.GetVariantVector();
        return;
    case VAR_VARIANTMAP:
        value = loKeyFrame.value_.GetVariantMap();
        return;
    case VAR_INTRECT:
        value = loKeyFrame.value_.GetIntRect();
        return;
    case VAR_INTVECTOR2:
        value = loKeyFrame.value_.GetIntVector2();
        return;
    case VAR_PTR:
        value = loKeyFrame.value_.GetPtr();
        return;
    }
}

}
<|endoftext|>


<commit_before>#define __STDC_FORMAT_MACROS

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#include <unordered_map>
#include <map>

#include "include/types.h"
#include "include/sampler.h"

static bool stacktrace_mode = true;
static bool ignoreidle_mode = false;

static void __attribute__((noreturn))
edie(const char* errstr, ...)
{
  va_list ap;

  va_start(ap, errstr);
  vfprintf(stderr, errstr, ap);
  va_end(ap);
  fprintf(stderr, ": %s\n", strerror(errno));
  exit(EXIT_FAILURE);
}

class Addr2line {
private:
  int _out, _in;

public:
  explicit Addr2line(const char* path);
  ~Addr2line();
  int lookup(uint64_t pc, char** func, char** file, int* line) const;
};

#ifdef __APPLE__
static char* xstrndup(const char* str, size_t len)
{
  char* r;

  r = (char*) malloc(len + 1);
  if (r == NULL)
    return r;
  memcpy(r, str, len);
  r[len] = 0;
  return r;
}
#else
#define xstrndup strndup
#endif

Addr2line::Addr2line(const char* path)
{
  static const char* addr2line_exe[] = {
    "addr2line",
    "x86_64-jos-elf-addr2line",
  };

  int out[2], in[2], check[2], child, r;

  if (pipe(out) < 0 || pipe(in) < 0 || pipe(check) < 0)
    edie("%s: pipe", __func__);
  if (fcntl(check[1], F_SETFD,
            fcntl(check[1], F_GETFD, 0) | FD_CLOEXEC) < 0)
    edie("%s: fcntl", __func__);

  child = fork();
  if (child < 0) {
    edie("%s: fork", __func__);
  } else if (child == 0) {
    unsigned int i;

    close(check[0]);
    dup2(out[0], 0);
    close(out[0]);
    close(out[1]);
    dup2(in[1], 1);
    close(in[0]);
    close(in[1]);

    for (i = 0; i < sizeof(addr2line_exe) / sizeof(addr2line_exe[0]); i++)
      r = execlp(addr2line_exe[i], addr2line_exe[i],
                 "-C", "-f", "-e", path, NULL);
    r = 1;
    assert(sizeof(r) == write(check[1], &r, sizeof(r)));
    exit(0);
  }
  close(out[0]);
  close(in[1]);
  close(check[1]);

  if (read(check[0], &r, sizeof(r)) != 0) {
    errno = r;
    edie("%s: exec", __func__);
  }
  close(check[0]);

  _out = out[1];
  _in = in[0];
}

Addr2line::~Addr2line()
{
  close(_in);
  close(_out);
}

int
Addr2line::lookup(uint64_t pc, char** func, char** file, int* line) const
{
  char buf[4096];
  int n = snprintf(buf, sizeof(buf), "%#"PRIx64"\n", pc);
  if (n != write(_out, buf, n))
    edie("%s: write", __func__);

  n = 0;
  while (1) {
    int r = read(_in, buf + n, sizeof(buf) - n - 1);
    if (r < 0)
      edie("%s: read", __func__);
    n += r;
    buf[n] = 0;

    int nls = 0;
    for (int i = 0; i < n; ++i)
      if (buf[i] == '\n')
        nls++;
    if (nls >= 2)
      break;
  }

  *func = *file = NULL;

  char* nl, *col, *end;
  nl = strchr(buf, '\n');
  *func = xstrndup(buf, nl - buf);
  col = strchr(nl, ':');
  if (!col)
    goto bad;
  *file = xstrndup(nl + 1, col - nl - 1);
  end = NULL;
  *line = strtol(col + 1, &end, 10);
  if (!end || *end != '\n')
    goto bad;

  return 0;

bad:
  free(*func);
  free(*file);
  *func = *file = NULL;
  *line = 0;
  return -1;
}

struct gt
{
  bool operator()(int x0, int x1) const
  {
    return x0 > x1;
  }
};

struct pmuevent_ops {
  size_t operator()(const pmuevent* x) const {
    size_t h = std::hash<u64>()(x->rip);
    if (!stacktrace_mode)
      return h;
    for (int i = 0; i < NTRACE; i++)
      h ^= std::hash<u64>()(x->trace[i]);
    return h;
  }

  bool operator() (const pmuevent* x0, const pmuevent* x1) const {
    if (x0->rip != x1->rip)
      return false;
    if (!stacktrace_mode)
      return true;
    for (int i = 0; i < NTRACE; i++)
      if (x0->trace[i] != x1->trace[i])
        return false;
    return true;
  }
};

static void
print_entry(Addr2line &addr2line, int count, struct pmuevent *e)
{
  char *func;
  char *file;
  int line;
  addr2line.lookup(e->rip, &func, &file, &line);
  printf("%-8u %4s %016"PRIx64" %s:%u %s\n",
         count, e->idle?"idle":"", e->rip, file, line, func);
  free(func);
  free(file);

  if (!stacktrace_mode)
    return;

  for (int i = 0; i < NTRACE; i++) {
    if (e->trace[i] == 0)
      break;
    addr2line.lookup(e->trace[i], &func, &file, &line);
    printf("              %016"PRIx64" %s:%u %s\n",
           e->trace[i], file, line, func);
    free(func);
    free(file);
  }

  printf("\n");
}

int
main(int ac, char **av)
{
  static const char *sample;
  static const char *elf;
  struct logheader *header;
  struct stat buf;
  char *x;
  int fd;

  if (ac < 3) {
    fprintf(stderr, "usage: %s sample-file elf-file\n", av[0]);
    exit(EXIT_FAILURE);
  }

  sample = av[1];
  elf = av[2];

  fd = open(sample, O_RDONLY);
  if (fd < 0) {
    perror("open");
    exit(EXIT_FAILURE);
  }

  Addr2line addr2line(elf);

  if (fstat(fd, &buf) < 0)
    edie("fstat");

  x = (char*)mmap(0, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  if (x == MAP_FAILED) {
    perror("mmap");
    exit(EXIT_FAILURE);
  }
  header = (struct logheader*)x;

  std::unordered_map<struct pmuevent*, int, pmuevent_ops, pmuevent_ops> map;
  for (u32 i = 0; i < header->ncpus; i++) {
    struct pmuevent *p;
    struct pmuevent *q;

    p = (struct pmuevent*)(x + header->cpu[i].offset);
    q = (struct pmuevent*)(x + header->cpu[i].offset + header->cpu[i].size);
    for (; p < q; p++) {
      if (ignoreidle_mode && p->idle)
        continue;
      auto it = map.find(p);
      if (it == map.end())
        map[p] = 1;
      else
        it->second = it->second + 1;
    }
  }

  std::map<int, struct pmuevent*, gt> sorted;
  for (std::pair<struct pmuevent* const, int> &p : map)
    sorted[p.second] = p.first;

  for (std::pair<const int, struct pmuevent*> &p : sorted)
    print_entry(addr2line, p.first, p.second);

  return 0;
}
<commit_msg>avoid c++11 string literal confusion<commit_after>#define __STDC_FORMAT_MACROS

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <assert.h>
#include <inttypes.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#include <unordered_map>
#include <map>

#include "include/types.h"
#include "include/sampler.h"

static bool stacktrace_mode = true;
static bool ignoreidle_mode = false;

static void __attribute__((noreturn))
edie(const char* errstr, ...)
{
  va_list ap;

  va_start(ap, errstr);
  vfprintf(stderr, errstr, ap);
  va_end(ap);
  fprintf(stderr, ": %s\n", strerror(errno));
  exit(EXIT_FAILURE);
}

class Addr2line {
private:
  int _out, _in;

public:
  explicit Addr2line(const char* path);
  ~Addr2line();
  int lookup(uint64_t pc, char** func, char** file, int* line) const;
};

#ifdef __APPLE__
static char* xstrndup(const char* str, size_t len)
{
  char* r;

  r = (char*) malloc(len + 1);
  if (r == NULL)
    return r;
  memcpy(r, str, len);
  r[len] = 0;
  return r;
}
#else
#define xstrndup strndup
#endif

Addr2line::Addr2line(const char* path)
{
  static const char* addr2line_exe[] = {
    "addr2line",
    "x86_64-jos-elf-addr2line",
  };

  int out[2], in[2], check[2], child, r;

  if (pipe(out) < 0 || pipe(in) < 0 || pipe(check) < 0)
    edie("%s: pipe", __func__);
  if (fcntl(check[1], F_SETFD,
            fcntl(check[1], F_GETFD, 0) | FD_CLOEXEC) < 0)
    edie("%s: fcntl", __func__);

  child = fork();
  if (child < 0) {
    edie("%s: fork", __func__);
  } else if (child == 0) {
    unsigned int i;

    close(check[0]);
    dup2(out[0], 0);
    close(out[0]);
    close(out[1]);
    dup2(in[1], 1);
    close(in[0]);
    close(in[1]);

    for (i = 0; i < sizeof(addr2line_exe) / sizeof(addr2line_exe[0]); i++)
      r = execlp(addr2line_exe[i], addr2line_exe[i],
                 "-C", "-f", "-e", path, NULL);
    r = 1;
    assert(sizeof(r) == write(check[1], &r, sizeof(r)));
    exit(0);
  }
  close(out[0]);
  close(in[1]);
  close(check[1]);

  if (read(check[0], &r, sizeof(r)) != 0) {
    errno = r;
    edie("%s: exec", __func__);
  }
  close(check[0]);

  _out = out[1];
  _in = in[0];
}

Addr2line::~Addr2line()
{
  close(_in);
  close(_out);
}

int
Addr2line::lookup(uint64_t pc, char** func, char** file, int* line) const
{
  char buf[4096];
  int n = snprintf(buf, sizeof(buf), "%#" PRIx64 "\n", pc);
  if (n != write(_out, buf, n))
    edie("%s: write", __func__);

  n = 0;
  while (1) {
    int r = read(_in, buf + n, sizeof(buf) - n - 1);
    if (r < 0)
      edie("%s: read", __func__);
    n += r;
    buf[n] = 0;

    int nls = 0;
    for (int i = 0; i < n; ++i)
      if (buf[i] == '\n')
        nls++;
    if (nls >= 2)
      break;
  }

  *func = *file = NULL;

  char* nl, *col, *end;
  nl = strchr(buf, '\n');
  *func = xstrndup(buf, nl - buf);
  col = strchr(nl, ':');
  if (!col)
    goto bad;
  *file = xstrndup(nl + 1, col - nl - 1);
  end = NULL;
  *line = strtol(col + 1, &end, 10);
  if (!end || *end != '\n')
    goto bad;

  return 0;

bad:
  free(*func);
  free(*file);
  *func = *file = NULL;
  *line = 0;
  return -1;
}

struct gt
{
  bool operator()(int x0, int x1) const
  {
    return x0 > x1;
  }
};

struct pmuevent_ops {
  size_t operator()(const pmuevent* x) const {
    size_t h = std::hash<u64>()(x->rip);
    if (!stacktrace_mode)
      return h;
    for (int i = 0; i < NTRACE; i++)
      h ^= std::hash<u64>()(x->trace[i]);
    return h;
  }

  bool operator() (const pmuevent* x0, const pmuevent* x1) const {
    if (x0->rip != x1->rip)
      return false;
    if (!stacktrace_mode)
      return true;
    for (int i = 0; i < NTRACE; i++)
      if (x0->trace[i] != x1->trace[i])
        return false;
    return true;
  }
};

static void
print_entry(Addr2line &addr2line, int count, struct pmuevent *e)
{
  char *func;
  char *file;
  int line;
  addr2line.lookup(e->rip, &func, &file, &line);
  printf("%-8u %4s %016" PRIx64 " %s:%u %s\n",
         count, e->idle?"idle":"", e->rip, file, line, func);
  free(func);
  free(file);

  if (!stacktrace_mode)
    return;

  for (int i = 0; i < NTRACE; i++) {
    if (e->trace[i] == 0)
      break;
    addr2line.lookup(e->trace[i], &func, &file, &line);
    printf("              %016" PRIx64 " %s:%u %s\n",
           e->trace[i], file, line, func);
    free(func);
    free(file);
  }

  printf("\n");
}

int
main(int ac, char **av)
{
  static const char *sample;
  static const char *elf;
  struct logheader *header;
  struct stat buf;
  char *x;
  int fd;

  if (ac < 3) {
    fprintf(stderr, "usage: %s sample-file elf-file\n", av[0]);
    exit(EXIT_FAILURE);
  }

  sample = av[1];
  elf = av[2];

  fd = open(sample, O_RDONLY);
  if (fd < 0) {
    perror("open");
    exit(EXIT_FAILURE);
  }

  Addr2line addr2line(elf);

  if (fstat(fd, &buf) < 0)
    edie("fstat");

  x = (char*)mmap(0, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
  if (x == MAP_FAILED) {
    perror("mmap");
    exit(EXIT_FAILURE);
  }
  header = (struct logheader*)x;

  std::unordered_map<struct pmuevent*, int, pmuevent_ops, pmuevent_ops> map;
  for (u32 i = 0; i < header->ncpus; i++) {
    struct pmuevent *p;
    struct pmuevent *q;

    p = (struct pmuevent*)(x + header->cpu[i].offset);
    q = (struct pmuevent*)(x + header->cpu[i].offset + header->cpu[i].size);
    for (; p < q; p++) {
      if (ignoreidle_mode && p->idle)
        continue;
      auto it = map.find(p);
      if (it == map.end())
        map[p] = 1;
      else
        it->second = it->second + 1;
    }
  }

  std::map<int, struct pmuevent*, gt> sorted;
  for (std::pair<struct pmuevent* const, int> &p : map)
    sorted[p.second] = p.first;

  for (std::pair<const int, struct pmuevent*> &p : sorted)
    print_entry(addr2line, p.first, p.second);

  return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/platform_thread.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"

#define NUMBER_OF_ITERATIONS 5

namespace {

// This Automated UI test opens static files in different tabs in a proxy
// browser. After all the tabs have opened, it switches between tabs, and notes
// time taken for each switch. It then prints out the times on the console,
// with the aim that the page cycler parser can interpret these numbers to
// draw graphs for page cycler Tab Switching Performance.
// Usage Flags: --enable-logging --dump-histograms-on-exit --log-level=0
class TabSwitchingUITest : public UITest {
 public:
  TabSwitchingUITest() {
    PathService::Get(base::DIR_SOURCE_ROOT, &path_prefix_);
    path_prefix_ = path_prefix_.AppendASCII("data");
    path_prefix_ = path_prefix_.AppendASCII("tab_switching");

    show_window_ = true;
  }

  void RunTabSwitchingUITest() {
    // Create a browser proxy.
    browser_proxy_ = automation()->GetBrowserWindow(0);

    // Open all the tabs.
    int initial_tab_count = 0;
    ASSERT_TRUE(browser_proxy_->GetTabCount(&initial_tab_count));
    int new_tab_count = OpenTabs();
    ASSERT_TRUE(browser_proxy_->WaitForTabCountToBecome(
        initial_tab_count + new_tab_count, 10000));

    // Switch linearly between tabs.
    browser_proxy_->ActivateTab(0);
    int final_tab_count = 0;
    ASSERT_TRUE(browser_proxy_->GetTabCount(&final_tab_count));
    for (int i = initial_tab_count; i < final_tab_count; ++i) {
      browser_proxy_->ActivateTab(i);
      ASSERT_TRUE(browser_proxy_->WaitForTabToBecomeActive(i, 10000));
    }

    // Close the browser to force a dump of log.
    bool application_closed = false;
    EXPECT_TRUE(CloseBrowser(browser_proxy_.get(), &application_closed));

    // Now open the corresponding log file and collect average and std dev from
    // the histogram stats generated for RenderWidgetHost_TabSwitchPaintDuration
    FilePath log_file_name;
    ASSERT_TRUE(PathService::Get(chrome::DIR_LOGS, &log_file_name));
    log_file_name = log_file_name.AppendASCII("chrome_debug.log");

    bool log_has_been_dumped = false;
    std::string contents;
    int max_tries = 20;
    do {
      log_has_been_dumped = file_util::ReadFileToString(log_file_name,
                                                        &contents);
      if (!log_has_been_dumped)
        PlatformThread::Sleep(100);
    } while (!log_has_been_dumped && max_tries--);
    ASSERT_TRUE(log_has_been_dumped) << "Failed to read the log file";

    // Parse the contents to get average and std deviation.
    std::string average("0.0"), std_dev("0.0");
    const std::string average_str("average = ");
    const std::string std_dev_str("standard deviation = ");
    std::string::size_type pos = contents.find(
        "Histogram: MPArch.RWH_TabSwitchPaintDuration", 0);
    std::string::size_type comma_pos;
    std::string::size_type number_length;

    ASSERT_NE(pos, std::string::npos) <<
      "Histogram: MPArch.RWH_TabSwitchPaintDuration wasn't found\n" <<
      contents;

    // Get the average.
    pos = contents.find(average_str, pos);
    comma_pos = contents.find(",", pos);
    pos += average_str.length();
    number_length = comma_pos - pos;
    average = contents.substr(pos, number_length);

    // Get the std dev.
    pos = contents.find(std_dev_str, pos);
    pos += std_dev_str.length();
    comma_pos = contents.find(" ", pos);
    number_length = comma_pos - pos;
    std_dev = contents.substr(pos, number_length);

    // Print the average and standard deviation.
    PrintResultMeanAndError("tab_switch", "", "t",
                            average + ", " + std_dev, "ms",
                            true /* important */);
  }

 protected:
  // Opens new tabs. Returns the number of tabs opened.
  int OpenTabs() {
    // Add tabs.
    static const char* files[] = { "espn.go.com", "bugzilla.mozilla.org",
                                   "news.cnet.com", "www.amazon.com",
                                   "kannada.chakradeo.net", "allegro.pl",
                                   "ml.wikipedia.org", "www.bbc.co.uk",
                                   "126.com", "www.altavista.com"};
    int number_of_new_tabs_opened = 0;
    FilePath file_name;
    for (size_t i = 0; i < arraysize(files); ++i) {
      file_name = path_prefix_;
      file_name = file_name.AppendASCII(files[i]);
      file_name = file_name.AppendASCII("index.html");
      browser_proxy_->AppendTab(net::FilePathToFileURL(file_name));
      number_of_new_tabs_opened++;
    }

    return number_of_new_tabs_opened;
  }

  FilePath path_prefix_;
  scoped_refptr<BrowserProxy> browser_proxy_;

 private:
  DISALLOW_COPY_AND_ASSIGN(TabSwitchingUITest);
};

TEST_F(TabSwitchingUITest, DISABLED_GenerateTabSwitchStats) {
  RunTabSwitchingUITest();
}

}  // namespace
<commit_msg>Re-enable tab switching test.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/platform_thread.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"

#define NUMBER_OF_ITERATIONS 5

namespace {

// This Automated UI test opens static files in different tabs in a proxy
// browser. After all the tabs have opened, it switches between tabs, and notes
// time taken for each switch. It then prints out the times on the console,
// with the aim that the page cycler parser can interpret these numbers to
// draw graphs for page cycler Tab Switching Performance.
// Usage Flags: --enable-logging --dump-histograms-on-exit --log-level=0
class TabSwitchingUITest : public UITest {
 public:
  TabSwitchingUITest() {
    PathService::Get(base::DIR_SOURCE_ROOT, &path_prefix_);
    path_prefix_ = path_prefix_.AppendASCII("data");
    path_prefix_ = path_prefix_.AppendASCII("tab_switching");

    show_window_ = true;
  }

  void RunTabSwitchingUITest() {
    // Create a browser proxy.
    browser_proxy_ = automation()->GetBrowserWindow(0);

    // Open all the tabs.
    int initial_tab_count = 0;
    ASSERT_TRUE(browser_proxy_->GetTabCount(&initial_tab_count));
    int new_tab_count = OpenTabs();
    ASSERT_TRUE(browser_proxy_->WaitForTabCountToBecome(
        initial_tab_count + new_tab_count, 10000));

    // Switch linearly between tabs.
    browser_proxy_->ActivateTab(0);
    int final_tab_count = 0;
    ASSERT_TRUE(browser_proxy_->GetTabCount(&final_tab_count));
    for (int i = initial_tab_count; i < final_tab_count; ++i) {
      browser_proxy_->ActivateTab(i);
      ASSERT_TRUE(browser_proxy_->WaitForTabToBecomeActive(i, 10000));
    }

    // Close the browser to force a dump of log.
    bool application_closed = false;
    EXPECT_TRUE(CloseBrowser(browser_proxy_.get(), &application_closed));

    // Now open the corresponding log file and collect average and std dev from
    // the histogram stats generated for RenderWidgetHost_TabSwitchPaintDuration
    FilePath log_file_name;
    ASSERT_TRUE(PathService::Get(chrome::DIR_LOGS, &log_file_name));
    log_file_name = log_file_name.AppendASCII("chrome_debug.log");

    bool log_has_been_dumped = false;
    std::string contents;
    int max_tries = 20;
    do {
      log_has_been_dumped = file_util::ReadFileToString(log_file_name,
                                                        &contents);
      if (!log_has_been_dumped)
        PlatformThread::Sleep(100);
    } while (!log_has_been_dumped && max_tries--);
    ASSERT_TRUE(log_has_been_dumped) << "Failed to read the log file";

    // Parse the contents to get average and std deviation.
    std::string average("0.0"), std_dev("0.0");
    const std::string average_str("average = ");
    const std::string std_dev_str("standard deviation = ");
    std::string::size_type pos = contents.find(
        "Histogram: MPArch.RWH_TabSwitchPaintDuration", 0);
    std::string::size_type comma_pos;
    std::string::size_type number_length;

    ASSERT_NE(pos, std::string::npos) <<
      "Histogram: MPArch.RWH_TabSwitchPaintDuration wasn't found\n" <<
      contents;

    // Get the average.
    pos = contents.find(average_str, pos);
    comma_pos = contents.find(",", pos);
    pos += average_str.length();
    number_length = comma_pos - pos;
    average = contents.substr(pos, number_length);

    // Get the std dev.
    pos = contents.find(std_dev_str, pos);
    pos += std_dev_str.length();
    comma_pos = contents.find(" ", pos);
    number_length = comma_pos - pos;
    std_dev = contents.substr(pos, number_length);

    // Print the average and standard deviation.
    PrintResultMeanAndError("tab_switch", "", "t",
                            average + ", " + std_dev, "ms",
                            true /* important */);
  }

 protected:
  // Opens new tabs. Returns the number of tabs opened.
  int OpenTabs() {
    // Add tabs.
    static const char* files[] = { "espn.go.com", "bugzilla.mozilla.org",
                                   "news.cnet.com", "www.amazon.com",
                                   "kannada.chakradeo.net", "allegro.pl",
                                   "ml.wikipedia.org", "www.bbc.co.uk",
                                   "126.com", "www.altavista.com"};
    int number_of_new_tabs_opened = 0;
    FilePath file_name;
    for (size_t i = 0; i < arraysize(files); ++i) {
      file_name = path_prefix_;
      file_name = file_name.AppendASCII(files[i]);
      file_name = file_name.AppendASCII("index.html");
      browser_proxy_->AppendTab(net::FilePathToFileURL(file_name));
      number_of_new_tabs_opened++;
    }

    return number_of_new_tabs_opened;
  }

  FilePath path_prefix_;
  scoped_refptr<BrowserProxy> browser_proxy_;

 private:
  DISALLOW_COPY_AND_ASSIGN(TabSwitchingUITest);
};

TEST_F(TabSwitchingUITest, GenerateTabSwitchStats) {
  RunTabSwitchingUITest();
}

}  // namespace
<|endoftext|>


<commit_before>#include "math/Vec2.h"

#include "math/Vec3.h"

using fei::Vec2;

Vec2::Vec2(float xy)
: x(xy), y(xy)
{
}

Vec2::Vec2(const fei::Vec3& v3)
: x(v3.x), y(v3.y)
{
}

Vec2::Vec2(float xx, float yy)
: x(xx), y(yy)
{
}

float Vec2::getAngle() const
{
	//TODO: need optimization
	if (std::abs(x) < fei::eps) {
		if (std::abs(y) < fei::eps || y > 0) {
			return 0.0f;
		} else {
			return 180.0f;
		}
	}
	float ans = std::atan(y / x);
	if (x >= 0) ans += fei::pif * 1.5f;
	else ans += fei::pif * 0.5f;
	ans *= 180.0f / fei::pif;
	return ans;
}

const Vec2 Vec2::getVerticalVec2() const
{
	fei::Vec3 v3(*this, 0.0f);
	v3 = v3.cross(Vec3(Vec2::ZERO, 1.0f));
	Vec2 ret = Vec2(v3);
	ret.normalize();
	return ret;
}

const Vec2 Vec2::ZERO  = Vec2(0.0f);
const Vec2 Vec2::ONE = Vec2(1.0f);
const Vec2 Vec2::UP    = Vec2(0.0f, 1.0f);
const Vec2 Vec2::DOWN  = Vec2(0.0f, -1.0f);
const Vec2 Vec2::LEFT  = Vec2(-1.0f, 0.0f);
const Vec2 Vec2::RIGHT = Vec2(1.0f, 0.0f);

<commit_msg>update Vec2::getAngle<commit_after>#include "math/Vec2.h"

#include "math/Vec3.h"

using fei::Vec2;

Vec2::Vec2(float xy)
: x(xy), y(xy)
{
}

Vec2::Vec2(const fei::Vec3& v3)
: x(v3.x), y(v3.y)
{
}

Vec2::Vec2(float xx, float yy)
: x(xx), y(yy)
{
}

float Vec2::getAngle() const
{
	//TODO: need optimization
	if (std::abs(x) < fei::eps) {
		if (std::abs(y) < fei::eps || y > 0) {
			return 0.0f;
		} else {
			return fei::pif;
		}
	}
	float ans = std::atan(y / x);
	if (x >= 0) ans += fei::pif * 1.5f;
	else ans += fei::pif * 0.5f;
	return ans;
}

const Vec2 Vec2::getVerticalVec2() const
{
	fei::Vec3 v3(*this, 0.0f);
	v3 = v3.cross(Vec3(Vec2::ZERO, 1.0f));
	Vec2 ret = Vec2(v3);
	ret.normalize();
	return ret;
}

const Vec2 Vec2::ZERO  = Vec2(0.0f);
const Vec2 Vec2::ONE = Vec2(1.0f);
const Vec2 Vec2::UP    = Vec2(0.0f, 1.0f);
const Vec2 Vec2::DOWN  = Vec2(0.0f, -1.0f);
const Vec2 Vec2::LEFT  = Vec2(-1.0f, 0.0f);
const Vec2 Vec2::RIGHT = Vec2(1.0f, 0.0f);

<|endoftext|>


<commit_before>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

// A C++ binary to benchmark a compute graph and its individual operators,
// both on desktop machines and on Android.
//
// See README.md for usage instructions.

#include "tensorflow/tools/benchmark/benchmark_model.h"

#include <cstdlib>
#include <memory>
#include <string>
#include <unordered_set>
#include <vector>

#include "tensorflow/core/framework/graph.pb.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/graph/algorithm.h"
#include "tensorflow/core/graph/graph.h"
#include "tensorflow/core/graph/graph_constructor.h"
#include "tensorflow/core/lib/strings/str_util.h"
#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/init_main.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/types.h"
#include "tensorflow/core/public/session.h"
#include "tensorflow/core/util/command_line_flags.h"
#include "tensorflow/core/util/reporter.h"
#include "tensorflow/core/util/stat_summarizer.h"

namespace tensorflow {
namespace benchmark_model {

Status InitializeSession(int num_threads, const string& graph,
                         std::unique_ptr<Session>* session,
                         std::unique_ptr<StatSummarizer>* stats) {
  LOG(INFO) << "Loading TensorFlow.";

  tensorflow::SessionOptions options;
  tensorflow::ConfigProto& config = options.config;
  if (num_threads > 0) {
    config.set_intra_op_parallelism_threads(num_threads);
  }
  LOG(INFO) << "Got config, " << config.device_count_size() << " devices";

  session->reset(tensorflow::NewSession(options));
  tensorflow::GraphDef tensorflow_graph;
  Status s = ReadBinaryProto(Env::Default(), graph, &tensorflow_graph);
  if (!s.ok()) {
    LOG(ERROR) << "Could not create TensorFlow Graph: " << s;
    return s;
  }

  stats->reset(new tensorflow::StatSummarizer(tensorflow_graph));

  s = (*session)->Create(tensorflow_graph);
  if (!s.ok()) {
    LOG(ERROR) << "Could not create TensorFlow Session: " << s;
    return s;
  }

  // Clear the proto to save memory space.
  tensorflow_graph.Clear();
  return Status::OK();
}

Status RunBenchmark(const std::vector<InputLayerInfo>& inputs,
                    const std::vector<string>& outputs, Session* session,
                    StatSummarizer* stats) {
  std::vector<std::pair<string, tensorflow::Tensor> > input_tensors;
  for (const InputLayerInfo& input : inputs) {
    Tensor input_tensor(input.data_type, input.shape);
    switch (input.data_type) {
      case DT_INT32: {
        auto int_tensor = input_tensor.flat<int32>();
        int_tensor = int_tensor.constant(0.0);
        break;
      }
      case DT_FLOAT: {
        auto float_tensor = input_tensor.flat<float>();
        float_tensor = float_tensor.constant(0.0);
        break;
      }
      case DT_QUINT8: {
        auto int_tensor = input_tensor.flat<quint8>();
        int_tensor = int_tensor.constant(0.0);
        break;
      }
      default:
        LOG(FATAL) << "Unsupported input type: " << input.data_type;
    }
    input_tensors.push_back({input.name, input_tensor});
  }

  std::vector<tensorflow::Tensor> output_tensors;

  tensorflow::Status s;

  RunOptions run_options;
  run_options.set_trace_level(RunOptions::FULL_TRACE);
  RunMetadata run_metadata;

  s = session->Run(run_options, input_tensors, outputs, {}, &output_tensors,
                   &run_metadata);

  if (!s.ok()) {
    LOG(ERROR) << "Error during inference: " << s;
  }

  assert(run_metadata.has_step_stats());

  const StepStats& step_stats = run_metadata.step_stats();

  stats->ProcessStepStats(step_stats);

  return s;
}

Status TimeMultipleRuns(double sleep_seconds, int num_runs,
                        const std::vector<InputLayerInfo>& inputs,
                        const std::vector<string>& outputs, Session* session,
                        StatSummarizer* stats) {
  // Convert the run_delay string into a timespec.
  timespec req;
  req.tv_sec = static_cast<time_t>(sleep_seconds);
  req.tv_nsec = (sleep_seconds - req.tv_sec) * 1000000000;

  LOG(INFO) << "Running benchmark";
  for (int i = 0; i < num_runs; ++i) {
    Status run_status = RunBenchmark(inputs, outputs, session, stats);
    if (!run_status.ok()) {
      LOG(INFO) << "Failed on run " << i;
      return run_status;
    }

    // If requested, sleep between runs for an arbitrary amount of time.
    // This can be helpful to determine the effect of mobile processor
    // scaling and thermal throttling.
    if (sleep_seconds > 0.0) {
      nanosleep(&req, nullptr);
    }
  }

  return Status::OK();
}

int Main(int argc, char** argv) {
  string graph = "/data/local/tmp/tensorflow_inception_graph.pb";
  string input_layer_string = "input:0";
  string input_layer_shape_string = "1,224,224,3";
  string input_layer_type_string = "float";
  string output_layer_string = "output:0";
  int num_runs = 50;
  string run_delay = "-1.0";
  int num_threads = -1;
  string benchmark_name = "";
  string output_prefix = "";
  bool show_sizes = false;

  std::vector<Flag> flag_list = {
      Flag("graph", &graph, "graph file name"),
      Flag("input_layer", &input_layer_string, "input layer names"),
      Flag("input_layer_shape", &input_layer_shape_string, "input layer shape"),
      Flag("input_layer_type", &input_layer_type_string, "input layer type"),
      Flag("output_layer", &output_layer_string, "output layer name"),
      Flag("num_runs", &num_runs, "number of runs"),
      Flag("run_delay", &run_delay, "delay between runs in seconds"),
      Flag("num_threads", &num_threads, "number of threads"),
      Flag("benchmark_name", &benchmark_name, "benchmark name"),
      Flag("output_prefix", &output_prefix, "benchmark output prefix"),
      Flag("show_sizes", &show_sizes, "whether to show sizes"),
  };
  string usage = Flags::Usage(argv[0], flag_list);
  const bool parse_result = Flags::Parse(&argc, argv, flag_list);

  if (!parse_result) {
    LOG(ERROR) << usage;
    return -1;
  }

  std::vector<string> input_layers = str_util::Split(input_layer_string, ',');
  std::vector<string> input_layer_shapes =
      str_util::Split(input_layer_shape_string, ':');
  std::vector<string> input_layer_types =
      str_util::Split(input_layer_type_string, ',');
  std::vector<string> output_layers = str_util::Split(output_layer_string, ',');
  if ((input_layers.size() != input_layer_shapes.size()) ||
      (input_layers.size() != input_layer_types.size())) {
    LOG(ERROR) << "There must be the same number of items in --input_layer,"
               << " --input_layer_shape, and --input_layer_type, for example"
               << " --input_layer=input1,input2 --input_layer_type=float,float "
               << " --input_layer_shape=1,224,224,4:1,20";
    LOG(ERROR) << "--input_layer=" << input_layer_string << " ("
               << input_layers.size() << " items)";
    LOG(ERROR) << "--input_layer_type=" << input_layer_type_string << " ("
               << input_layer_types.size() << " items)";
    LOG(ERROR) << "--input_layer_shape=" << input_layer_shape_string << " ("
               << input_layer_shapes.size() << " items)";
    return -1;
  }
  const size_t inputs_count = input_layers.size();

  ::tensorflow::port::InitMain(argv[0], &argc, &argv);
  if (argc > 1) {
    LOG(ERROR) << "Unknown argument " << argv[1] << "\n" << usage;
    return -1;
  }

  LOG(INFO) << "Graph: [" << graph << "]";
  LOG(INFO) << "Input layers: [" << input_layer_string << "]";
  LOG(INFO) << "Input shapes: [" << input_layer_shape_string << "]";
  LOG(INFO) << "Input types: [" << input_layer_type_string << "]";
  LOG(INFO) << "Output layers: [" << output_layer_string << "]";
  LOG(INFO) << "Num runs: [" << num_runs << "]";
  LOG(INFO) << "Inter-run delay (seconds): [" << run_delay << "]";
  LOG(INFO) << "Num threads: [" << num_threads << "]";
  LOG(INFO) << "Benchmark name: [" << benchmark_name << "]";
  LOG(INFO) << "Output prefix: [" << output_prefix << "]";
  LOG(INFO) << "Show sizes: [" << show_sizes << "]";

  std::unique_ptr<Session> session;
  std::unique_ptr<StatSummarizer> stats;
  Status initialize_status =
      InitializeSession(num_threads, graph, &session, &stats);
  if (!initialize_status.ok()) {
    return -1;
  }

  const double sleep_seconds = std::strtod(run_delay.c_str(), nullptr);

  std::vector<InputLayerInfo> inputs;
  for (int n = 0; n < inputs_count; ++n) {
    InputLayerInfo input;
    CHECK(DataTypeFromString(input_layer_types[n], &input.data_type))
        << input_layer_types[n] << " was an invalid type";
    std::vector<int32> sizes;
    CHECK(str_util::SplitAndParseAsInts(input_layer_shapes[n], ',', &sizes))
        << "Incorrect size string specified: " << input_layer_shapes[n];
    for (int i = 0; i < sizes.size(); ++i) {
      input.shape.AddDim(sizes[i]);
    }
    input.name = input_layers[n];
    inputs.push_back(input);
  }

  const int64 start_time = Env::Default()->NowMicros();
  Status time_status =
      TimeMultipleRuns(sleep_seconds, num_runs, inputs, output_layers,
                       session.get(), stats.get());
  const int64 end_time = Env::Default()->NowMicros();
  const double wall_time = (end_time - start_time) / 1000000.0;

  if (!time_status.ok()) {
    LOG(ERROR) << "Timing failed with " << time_status;
    return -1;
  }

  stats->PrintStepStats();

  if (show_sizes) {
    stats->PrintOutputs();
  }

  if (!benchmark_name.empty() && !output_prefix.empty()) {
    // Compute the total number of values per input.
    int64 total_size = inputs[0].shape.num_elements();

    // Throughput in MB/s
    const double throughput = DataTypeSize(inputs[0].data_type) * total_size *
                              num_runs / static_cast<double>(wall_time) /
                              (1024 * 1024);

    // Report the stats.
    TestReporter reporter(output_prefix, benchmark_name);
    reporter.Initialize();
    reporter.Benchmark(num_runs, -1.0, wall_time, throughput);
    reporter.Close();
  }

  return 0;
}

}  // namespace benchmark_model
}  // namespace tensorflow
<commit_msg>Add support for benchmarking with uint8 input types. Change: 140568567<commit_after>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

// A C++ binary to benchmark a compute graph and its individual operators,
// both on desktop machines and on Android.
//
// See README.md for usage instructions.

#include "tensorflow/tools/benchmark/benchmark_model.h"

#include <cstdlib>
#include <memory>
#include <string>
#include <unordered_set>
#include <vector>

#include "tensorflow/core/framework/graph.pb.h"
#include "tensorflow/core/framework/tensor.h"
#include "tensorflow/core/graph/algorithm.h"
#include "tensorflow/core/graph/graph.h"
#include "tensorflow/core/graph/graph_constructor.h"
#include "tensorflow/core/lib/strings/str_util.h"
#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/init_main.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/types.h"
#include "tensorflow/core/public/session.h"
#include "tensorflow/core/util/command_line_flags.h"
#include "tensorflow/core/util/reporter.h"
#include "tensorflow/core/util/stat_summarizer.h"

namespace tensorflow {
namespace benchmark_model {

Status InitializeSession(int num_threads, const string& graph,
                         std::unique_ptr<Session>* session,
                         std::unique_ptr<StatSummarizer>* stats) {
  LOG(INFO) << "Loading TensorFlow.";

  tensorflow::SessionOptions options;
  tensorflow::ConfigProto& config = options.config;
  if (num_threads > 0) {
    config.set_intra_op_parallelism_threads(num_threads);
  }
  LOG(INFO) << "Got config, " << config.device_count_size() << " devices";

  session->reset(tensorflow::NewSession(options));
  tensorflow::GraphDef tensorflow_graph;
  Status s = ReadBinaryProto(Env::Default(), graph, &tensorflow_graph);
  if (!s.ok()) {
    LOG(ERROR) << "Could not create TensorFlow Graph: " << s;
    return s;
  }

  stats->reset(new tensorflow::StatSummarizer(tensorflow_graph));

  s = (*session)->Create(tensorflow_graph);
  if (!s.ok()) {
    LOG(ERROR) << "Could not create TensorFlow Session: " << s;
    return s;
  }

  // Clear the proto to save memory space.
  tensorflow_graph.Clear();
  return Status::OK();
}

Status RunBenchmark(const std::vector<InputLayerInfo>& inputs,
                    const std::vector<string>& outputs, Session* session,
                    StatSummarizer* stats) {
  std::vector<std::pair<string, tensorflow::Tensor> > input_tensors;
  for (const InputLayerInfo& input : inputs) {
    Tensor input_tensor(input.data_type, input.shape);
    switch (input.data_type) {
      case DT_INT32: {
        auto int_tensor = input_tensor.flat<int32>();
        int_tensor = int_tensor.constant(0.0);
        break;
      }
      case DT_FLOAT: {
        auto float_tensor = input_tensor.flat<float>();
        float_tensor = float_tensor.constant(0.0);
        break;
      }
      case DT_QUINT8: {
        auto int_tensor = input_tensor.flat<quint8>();
        int_tensor = int_tensor.constant(0.0);
        break;
      }
      case DT_UINT8: {
        auto int_tensor = input_tensor.flat<uint8>();
        int_tensor = int_tensor.constant(0.0);
        break;
      }
      default:
        LOG(FATAL) << "Unsupported input type: " << input.data_type;
    }
    input_tensors.push_back({input.name, input_tensor});
  }

  std::vector<tensorflow::Tensor> output_tensors;

  tensorflow::Status s;

  RunOptions run_options;
  run_options.set_trace_level(RunOptions::FULL_TRACE);
  RunMetadata run_metadata;

  s = session->Run(run_options, input_tensors, outputs, {}, &output_tensors,
                   &run_metadata);

  if (!s.ok()) {
    LOG(ERROR) << "Error during inference: " << s;
  }

  assert(run_metadata.has_step_stats());

  const StepStats& step_stats = run_metadata.step_stats();

  stats->ProcessStepStats(step_stats);

  return s;
}

Status TimeMultipleRuns(double sleep_seconds, int num_runs,
                        const std::vector<InputLayerInfo>& inputs,
                        const std::vector<string>& outputs, Session* session,
                        StatSummarizer* stats) {
  // Convert the run_delay string into a timespec.
  timespec req;
  req.tv_sec = static_cast<time_t>(sleep_seconds);
  req.tv_nsec = (sleep_seconds - req.tv_sec) * 1000000000;

  LOG(INFO) << "Running benchmark";
  for (int i = 0; i < num_runs; ++i) {
    Status run_status = RunBenchmark(inputs, outputs, session, stats);
    if (!run_status.ok()) {
      LOG(INFO) << "Failed on run " << i;
      return run_status;
    }

    // If requested, sleep between runs for an arbitrary amount of time.
    // This can be helpful to determine the effect of mobile processor
    // scaling and thermal throttling.
    if (sleep_seconds > 0.0) {
      nanosleep(&req, nullptr);
    }
  }

  return Status::OK();
}

int Main(int argc, char** argv) {
  string graph = "/data/local/tmp/tensorflow_inception_graph.pb";
  string input_layer_string = "input:0";
  string input_layer_shape_string = "1,224,224,3";
  string input_layer_type_string = "float";
  string output_layer_string = "output:0";
  int num_runs = 50;
  string run_delay = "-1.0";
  int num_threads = -1;
  string benchmark_name = "";
  string output_prefix = "";
  bool show_sizes = false;

  std::vector<Flag> flag_list = {
      Flag("graph", &graph, "graph file name"),
      Flag("input_layer", &input_layer_string, "input layer names"),
      Flag("input_layer_shape", &input_layer_shape_string, "input layer shape"),
      Flag("input_layer_type", &input_layer_type_string, "input layer type"),
      Flag("output_layer", &output_layer_string, "output layer name"),
      Flag("num_runs", &num_runs, "number of runs"),
      Flag("run_delay", &run_delay, "delay between runs in seconds"),
      Flag("num_threads", &num_threads, "number of threads"),
      Flag("benchmark_name", &benchmark_name, "benchmark name"),
      Flag("output_prefix", &output_prefix, "benchmark output prefix"),
      Flag("show_sizes", &show_sizes, "whether to show sizes"),
  };
  string usage = Flags::Usage(argv[0], flag_list);
  const bool parse_result = Flags::Parse(&argc, argv, flag_list);

  if (!parse_result) {
    LOG(ERROR) << usage;
    return -1;
  }

  std::vector<string> input_layers = str_util::Split(input_layer_string, ',');
  std::vector<string> input_layer_shapes =
      str_util::Split(input_layer_shape_string, ':');
  std::vector<string> input_layer_types =
      str_util::Split(input_layer_type_string, ',');
  std::vector<string> output_layers = str_util::Split(output_layer_string, ',');
  if ((input_layers.size() != input_layer_shapes.size()) ||
      (input_layers.size() != input_layer_types.size())) {
    LOG(ERROR) << "There must be the same number of items in --input_layer,"
               << " --input_layer_shape, and --input_layer_type, for example"
               << " --input_layer=input1,input2 --input_layer_type=float,float "
               << " --input_layer_shape=1,224,224,4:1,20";
    LOG(ERROR) << "--input_layer=" << input_layer_string << " ("
               << input_layers.size() << " items)";
    LOG(ERROR) << "--input_layer_type=" << input_layer_type_string << " ("
               << input_layer_types.size() << " items)";
    LOG(ERROR) << "--input_layer_shape=" << input_layer_shape_string << " ("
               << input_layer_shapes.size() << " items)";
    return -1;
  }
  const size_t inputs_count = input_layers.size();

  ::tensorflow::port::InitMain(argv[0], &argc, &argv);
  if (argc > 1) {
    LOG(ERROR) << "Unknown argument " << argv[1] << "\n" << usage;
    return -1;
  }

  LOG(INFO) << "Graph: [" << graph << "]";
  LOG(INFO) << "Input layers: [" << input_layer_string << "]";
  LOG(INFO) << "Input shapes: [" << input_layer_shape_string << "]";
  LOG(INFO) << "Input types: [" << input_layer_type_string << "]";
  LOG(INFO) << "Output layers: [" << output_layer_string << "]";
  LOG(INFO) << "Num runs: [" << num_runs << "]";
  LOG(INFO) << "Inter-run delay (seconds): [" << run_delay << "]";
  LOG(INFO) << "Num threads: [" << num_threads << "]";
  LOG(INFO) << "Benchmark name: [" << benchmark_name << "]";
  LOG(INFO) << "Output prefix: [" << output_prefix << "]";
  LOG(INFO) << "Show sizes: [" << show_sizes << "]";

  std::unique_ptr<Session> session;
  std::unique_ptr<StatSummarizer> stats;
  Status initialize_status =
      InitializeSession(num_threads, graph, &session, &stats);
  if (!initialize_status.ok()) {
    return -1;
  }

  const double sleep_seconds = std::strtod(run_delay.c_str(), nullptr);

  std::vector<InputLayerInfo> inputs;
  for (int n = 0; n < inputs_count; ++n) {
    InputLayerInfo input;
    CHECK(DataTypeFromString(input_layer_types[n], &input.data_type))
        << input_layer_types[n] << " was an invalid type";
    std::vector<int32> sizes;
    CHECK(str_util::SplitAndParseAsInts(input_layer_shapes[n], ',', &sizes))
        << "Incorrect size string specified: " << input_layer_shapes[n];
    for (int i = 0; i < sizes.size(); ++i) {
      input.shape.AddDim(sizes[i]);
    }
    input.name = input_layers[n];
    inputs.push_back(input);
  }

  const int64 start_time = Env::Default()->NowMicros();
  Status time_status =
      TimeMultipleRuns(sleep_seconds, num_runs, inputs, output_layers,
                       session.get(), stats.get());
  const int64 end_time = Env::Default()->NowMicros();
  const double wall_time = (end_time - start_time) / 1000000.0;

  if (!time_status.ok()) {
    LOG(ERROR) << "Timing failed with " << time_status;
    return -1;
  }

  stats->PrintStepStats();

  if (show_sizes) {
    stats->PrintOutputs();
  }

  if (!benchmark_name.empty() && !output_prefix.empty()) {
    // Compute the total number of values per input.
    int64 total_size = inputs[0].shape.num_elements();

    // Throughput in MB/s
    const double throughput = DataTypeSize(inputs[0].data_type) * total_size *
                              num_runs / static_cast<double>(wall_time) /
                              (1024 * 1024);

    // Report the stats.
    TestReporter reporter(output_prefix, benchmark_name);
    reporter.Initialize();
    reporter.Benchmark(num_runs, -1.0, wall_time, throughput);
    reporter.Close();
  }

  return 0;
}

}  // namespace benchmark_model
}  // namespace tensorflow
<|endoftext|>