<commit_before>#pragma once

#include <array>
#include "MotionController.hpp"
#include "Pid.hpp"
#include "RobotModel.hpp"

/**
 * Robot controller that runs a PID loop on each of the four wheels.
 */
class PidMotionController : public MotionController {
public:
    PidMotionController() {
        setPidValues(1, 0, 0);

        for (auto& ctrl : _controllers) {
            ctrl.setWindup(5);
        }
    }

    void setPidValues(float p, float i, float d) {
        for (Pid& ctl : _controllers) {
            ctl.kp = p;
            ctl.ki = i;
            ctl.kd = d;
        }
    }

    /**
     * Return the duty cycle values for the motors to drive at the target
     * velocity.
     *
     * @param encoderDeltas Encoder deltas for the four drive motors
     * @param dt Time in ms since the last calll to run()
     *
     * @return Duty cycle values for each of the 4 motors
     */
    std::array<int16_t, 4> run(const std::array<int16_t, 4>& encoderDeltas,
                               float dt) {
        // convert encoder ticks to rad/s
        Eigen::Vector4f wheelVels;
        wheelVels << encoderDeltas[0], encoderDeltas[1], encoderDeltas[2],
            encoderDeltas[3];
        wheelVels *= 2 * M_PI / ENC_TICKS_PER_TURN / dt;

        Eigen::Vector4f targetWheelVels =
            RobotModel2015.BotToWheel * _targetVel;

        // printf("wheelVels[0] = %f\r\n", wheelVels[0]);

        // printf("targetWheelVels: %f, %f, %f, %f\r\n", targetWheelVels[0], targetWheelVels[1], targetWheelVels[2], targetWheelVels[3]);

        Eigen::Vector4f wheelVelErr = targetWheelVels - wheelVels;

        // printf("wheelVelErr:\r\n  ");
        // for (int i = 0; i < 4; i++) {
        //     printf("%f, ", wheelVelErr[i]);
        // }
        // printf("\r\n");

        std::array<int16_t, 4> dutyCycles;
        for (int i = 0; i < 4; i++) {
            int16_t dc =
                targetWheelVels[i] * RobotModel2015.DutyCycleMultiplier;
            dc += _controllers[i].run(wheelVelErr[i]);

            dutyCycles[i] = dc;
        }

        // printf("pid.run(), target.x = %f\r\n", _targetVel[0]);

        return dutyCycles;
    }

    static const uint16_t ENC_TICKS_PER_TURN = 2048;

private:
    /// controllers for each wheel
    Pid _controllers[4];
};

<commit_msg>more work on pid controller<commit_after>#pragma once

#include <array>
#include "MotionController.hpp"
#include "Pid.hpp"
#include "RobotModel.hpp"

/**
 * Robot controller that runs a PID loop on each of the four wheels.
 */
class PidMotionController : public MotionController {
public:
    PidMotionController() {
        setPidValues(1, 0, 0);

        for (auto& ctrl : _controllers) {
            ctrl.setWindup(5);
        }
    }

    void setPidValues(float p, float i, float d) {
        for (Pid& ctl : _controllers) {
            ctl.kp = p;
            ctl.ki = i;
            ctl.kd = d;
        }
    }

    /**
     * Return the duty cycle values for the motors to drive at the target
     * velocity.
     *
     * @param encoderDeltas Encoder deltas for the four drive motors
     * @param dt Time in ms since the last calll to run()
     *
     * @return Duty cycle values for each of the 4 motors
     */
    std::array<int16_t, 4> run(const std::array<int16_t, 4>& encoderDeltas,
                               float dt) {
        // convert encoder ticks to rad/s
        Eigen::Vector4f wheelVels;
        wheelVels <<
            encoderDeltas[0],
            encoderDeltas[1],
            encoderDeltas[2],
            encoderDeltas[3];
        wheelVels *= 2 * M_PI / ENC_TICKS_PER_TURN / dt;

        Eigen::Vector4f targetWheelVels =
            RobotModel2015.BotToWheel * _targetVel;

        Eigen::Vector4f wheelVelErr = targetWheelVels - wheelVels;

        std::array<int16_t, 4> dutyCycles;
        for (int i = 0; i < 4; i++) {
            int16_t dc =
                targetWheelVels[i] * RobotModel2015.DutyCycleMultiplier;
            dc += _controllers[i].run(wheelVelErr[i]);

            dutyCycles[i] = dc;
        }

        // enable these printouts to get a python-formatted data set than can be
        // graphed to visualize pid control and debug problems
#if 0
        printf("{\r\n");
        printf("'encDelt': [%d, %d, %d, %d],\r\n", encoderDeltas[0], encoderDeltas[1], encoderDeltas[2], encoderDeltas[3]);
        printf("'dt': %f,\r\n", dt);
        printf("'wheelVels': [%f, %f, %f, %f],\r\n", wheelVels[0], wheelVels[1], wheelVels[2], wheelVels[3]);
        printf("'targetWheelVels': [%f, %f, %f, %f],\r\n", targetWheelVels[0], targetWheelVels[1], targetWheelVels[2], targetWheelVels[3]);
        printf("'duty': [%d, %d, %d, %d],\r\n", dutyCycles[0], dutyCycles[1], dutyCycles[2], dutyCycles[3]);
        printf("},\r\n");
#endif

        return dutyCycles;
    }

    static const uint16_t ENC_TICKS_PER_TURN = 2048;

private:
    /// controllers for each wheel
    Pid _controllers[4];
};

<|endoftext|>


<commit_before>#include <vector>
#include <cassert>

#include "cprocessing.hpp"

typedef bool boolean;

#ifndef CPROCESSING_ARRAYLIST_
#define CPROCESSING_ARRAYLIST_

using namespace cprocessing;

namespace cprocessing {

    template <typename T>
    class ArrayList {
    public:
        std::vector<T> self;
        int maxSize;    //currently ignored

        ArrayList() {}

        ArrayList(int size) {
            self.reserve(size);
            maxSize = size;
        }

        ~ArrayList() {
            self.clear();
        }

        /**Adds element to ArrayList
         * @param e Element to add to end of ArrayList*/
        void add(T e) {
            self.push_back(e);
        }

        /**Inserts element into ArrayList at specific position
         * @param e Element to add to end of ArrayList\
         * @param index position in ArrayList*/
        void add(T e, int index) {
            self.insert(e, index);
        }

        /**Removes all elements from ArrayList*/
        void clear() {
            self.clear();
        }

        /**Copies ArrayList for your pleasure
         * @returns a copy of this ArrayList*/
        ArrayList clone() {
            return this;
        }

        /**Checks ArrayList if it contains an element (slow)
         * @param e Element to check if it is inside
         * @returns true if contains, false if not*/
        boolean contains(T e) {
            for(int i=0; i<self.size(); i++) {
                if(&self[i] == &e) return true;
            }
            return false;
        }

        //void ensureCapacity(int n);

        /**Grabs element from ArrayList for you to use
         * @param index position in ArrayList to grab from (0 - size())
         * @returns element at that index*/
        T * get(int index) {
            return &self[index];
        }

        /**Tells you the index position of a specific element
         * @param e element to check
         * @returns int between 0 - size(), or -1 if it isn't in this ArrayList*/
        int indexOf(T e) {
            for(int i=0; i<self.size(); i++) {
                if(&self[i] == &e) return i;
            }
            return -1;
        }

        /**Checks if ArrayList is empty, you can also check if size() == 0
         * @returns true if empty, otherwise false if there are elements in this ArrayList*/
        boolean isEmpty() {
            return ((self.size() == 0) ? true : false);
        }

        /**Tells you the last index position of a specific element
         * @param e element to check
         * @returns int between 0 - size(), or -1 if it isn't in this ArrayList*/
        int lastIndexOf(T e) {
            for(int i=self.size(); i>0; i--) {
                if(&self[i] == &e) return i;
            }
            return -1;
        }

        /**Removes an element from the ArrayList
         * @param index spot to remove from*/
        void remove(int index) {
            self.erase(self.begin()+index);
        }

        //remove by element is removed from this as it coincides with int

        /**Removes a group of elementsfrom the ArrayList from a start index to end index
         * @param start starting spot to remove from
         * @param end ending point to remove from */
        void removeRange(int start, int end) {
            self.erase(self.begin()+start, self.begin()+end);
        }

        /**Sets a spot in the ArrayList to something new
         * @param index spot to change
         * @param e element to set*/
        void set(int index, T e) {
            self[index] = e;
        }

        /**Gives you the size of the ArrayList (how many elements in it)
         * @returns amount of elements inside*/
        int size() {
            return self.size();
        }

        /**Converts ArrayList into an array
         * @returns array of all elements in ArrayList */
        T * toArray() {
            T r[self.size()];
            for(int i=0; i<self.size(); i++) {
                r[i] = self[i];
            }

            return r;
        }

        //void trimToSize(); //TODO

        /**Applies a function to all elements in ArrayList
         * @param *fp name of function to apply
         * @returns pointer to this ArrayList */
        ArrayList<T> * map(T (*fp)(T)) {
            for(int i=0; i<this->size(); i++)
                this->set(i, ((*fp)(*(this->get(i)))));
            return this;
        }

        /**Removes elements from ArrayList who do not meet condition of function
         * @param *fp name of function to compare elements to(boolean)
         * @returns pointer to this ArrayList */
        ArrayList<T> * filter(boolean (*fp)(T)) {
            ArrayList<T> out;
            for(int i=0; i<this->size(); i++)
                if(((*fp)(*(this->get(i))))) out.add(*(this->get(i)));
            this->self = out.self;
            return this;
        }

        /**Populates ArrayList by calling function from 0 -> n
         * @param *fp name of function to apply
         * @param n amount to add (usually int)
         * @returns pointer to this ArrayList */
        template <typename U>
        ArrayList<T> * populate(T (*fp)(U), U n) {
            assert(n >= 0);
            for(U i=0; i<n; i++)
                this->add(((*fp)(i)));
            return this;
        }

        /**Calls function with element as parameter
         * @param *fp name of function to call
         * @returns pointer to this ArrayList */
        template <typename U>
        ArrayList<T> * foreach(U (*fp)(T)) {
            for(int i=0; i<this->size(); i++)
                ((*fp)(*(this->get(i))));
            return this;
        }

        /**Calls function without breaking chain
         * @param *fp name of function to call
         * @returns pointer to this ArrayList */
        template <typename U>
        ArrayList<T> * call(U (*fp)()) {
            (*fp);
            return this;
        }

        /**Calls function without breaking chain, sends pointer of ArrayList to it
         * @param *fp name of function to call
         * @returns pointer to this ArrayList */
        template <typename U, typename V>
        ArrayList<T> * callback(U (*fp)(V)) {
            (*fp)(this);
            return this;
        }
    };
}

#endif<commit_msg>steal from haskell<commit_after>#include <vector>
#include <cassert>

#include "cprocessing.hpp"

typedef bool boolean;

#ifndef CPROCESSING_ARRAYLIST_
#define CPROCESSING_ARRAYLIST_

using namespace cprocessing;

namespace cprocessing {

    template <typename T>
    class ArrayList {
    public:
        std::vector<T> self;
        int maxSize;    //currently ignored

        ArrayList() {}

        ArrayList(int size) {
            self.reserve(size);
            maxSize = size;
        }

        ~ArrayList() {
            self.clear();
        }

        ArrayList<T>& operator= (const ArrayList<T>& a) {
            this->a = a.self;
            return (*this);
        }

        bool operator== (const ArrayList<T>& a)      {
            return ((this->self == a.self) ? true : false);
        }

        bool operator!= (const ArrayList<T>& a)      {
            return ((this->self != a.self) ? true : false);
        }

        ArrayList<T>& operator+ (const ArrayList<T>& a) {
            ArrayList<T> temp;
            temp = *(this);
            for(int i=0; i<a.size(); i++) {
                temp->add(*(a.get(i)));
            }
            return (*temp);
        }

        ArrayList<T>& operator+= (const ArrayList<T>& a) {
            for(int i=0; i<a.size(); i++) {
                this->add(*(a.get(i)));
            }
            return (*this);
        }

        /**Adds element to ArrayList
         * @param e Element to add to end of ArrayList*/
        void add(T e) {
            self.push_back(e);
        }

        /**Inserts element into ArrayList at specific position
         * @param e Element to add to end of ArrayList\
         * @param index position in ArrayList*/
        void add(T e, int index) {
            self.insert(e, index);
        }

        /**Removes all elements from ArrayList*/
        void clear() {
            self.clear();
        }

        /**Copies ArrayList for your pleasure
         * @returns a copy of this ArrayList*/
        ArrayList clone() {
            return this;
        }

        /**Checks ArrayList if it contains an element (slow)
         * @param e Element to check if it is inside
         * @returns true if contains, false if not*/
        boolean contains(T e) {
            for(int i=0; i<self.size(); i++) {
                if(&self[i] == &e) return true;
            }
            return false;
        }

        //void ensureCapacity(int n);

        /**Grabs element from ArrayList for you to use
         * @param index position in ArrayList to grab from (0 - size())
         * @returns element at that index*/
        T * get(int index) {
            return &self[index];
        }

        /**Tells you the index position of a specific element
         * @param e element to check
         * @returns int between 0 - size(), or -1 if it isn't in this ArrayList*/
        int indexOf(T e) {
            for(int i=0; i<self.size(); i++) {
                if(&self[i] == &e) return i;
            }
            return -1;
        }

        /**Checks if ArrayList is empty, you can also check if size() == 0
         * @returns true if empty, otherwise false if there are elements in this ArrayList*/
        boolean isEmpty() {
            return ((self.size() == 0) ? true : false);
        }

        /**Tells you the last index position of a specific element
         * @param e element to check
         * @returns int between 0 - size(), or -1 if it isn't in this ArrayList*/
        int lastIndexOf(T e) {
            for(int i=self.size(); i>0; i--) {
                if(&self[i] == &e) return i;
            }
            return -1;
        }

        /**Removes an element from the ArrayList
         * @param index spot to remove from*/
        void remove(int index) {
            self.erase(self.begin()+index);
        }

        //remove by element is removed from this as it coincides with int

        /**Removes a group of elementsfrom the ArrayList from a start index to end index
         * @param start starting spot to remove from
         * @param end ending point to remove from */
        void removeRange(int start, int end) {
            self.erase(self.begin()+start, self.begin()+end);
        }

        /**Sets a spot in the ArrayList to something new
         * @param index spot to change
         * @param e element to set*/
        void set(int index, T e) {
            self[index] = e;
        }

        /**Gives you the size of the ArrayList (how many elements in it)
         * @returns amount of elements inside*/
        int size() {
            return self.size();
        }

        /**Converts ArrayList into an array
         * @returns array of all elements in ArrayList */
        T * toArray() {
            T r[self.size()];
            for(int i=0; i<self.size(); i++) {
                r[i] = self[i];
            }

            return r;
        }

        //void trimToSize(); //TODO

        /**Applies a function to all elements in ArrayList
         * @param *fp name of function to apply
         * @returns pointer to this ArrayList */
        ArrayList<T> * map(T (*fp)(T)) {
            for(int i=0; i<this->size(); i++)
                this->set(i, ((*fp)(*(this->get(i)))));
            return this;
        }

        /**Removes elements from ArrayList who do not meet condition of function
         * @param *fp name of function to compare elements to(boolean)
         * @returns pointer to this ArrayList */
        ArrayList<T> * filter(boolean (*fp)(T)) {
            ArrayList<T> out;
            for(int i=0; i<this->size(); i++)
                if(((*fp)(*(this->get(i))))) out.add(*(this->get(i)));
            this->self = out.self;
            return this;
        }

        /**Populates ArrayList by calling function from 0 -> n
         * @param *fp name of function to apply
         * @param n amount to add (usually int)
         * @returns pointer to this ArrayList */
        template <typename U>
        ArrayList<T> * populate(T (*fp)(U), U n) {
            assert(n >= 0);
            for(U i=0; i<n; i++)
                this->add(((*fp)(i)));
            return this;
        }

        /**Calls function with element as parameter
         * @param *fp name of function to call
         * @returns pointer to this ArrayList */
        template <typename U>
        ArrayList<T> * foreach(U (*fp)(T)) {
            for(int i=0; i<this->size(); i++)
                ((*fp)(*(this->get(i))));
            return this;
        }

        /**Calls function without breaking chain
         * @param *fp name of function to call
         * @returns pointer to this ArrayList */
        template <typename U>
        ArrayList<T> * call(U (*fp)()) {
            (*fp);
            return this;
        }

        /**Calls function without breaking chain, sends pointer of ArrayList to it
         * @param *fp name of function to call
         * @returns pointer to this ArrayList */
        template <typename U, typename V>
        ArrayList<T> * callback(U (*fp)(V)) {
            (*fp)(this);
            return this;
        }

        T * head() {
            assert(size() > 0);
            return &get(0);
        }

        T * last() {
            assert(size() > 0);
            return &get(size()-1);
        }

        /*T * minimum() {   //TODO
            assert(size() > 0);
        }*/

        /*T * maximum() {   //TODO
            assert(size() > 0);
            return &get(size()-1);
        }*/

        T sum() {
            assert(size() > 0);
            T r = *(this->get(0));
            for(int i=1; i<this->size(); i++) r = r+*(this->get(i));
            return r;
        }

        T product() {
            assert(size() > 0);
            T r = *(this->get(0));
            for(int i=1; i<this->size(); i++) r = r*(*(this->get(i)));
            return r;
        }

        ArrayList<T> tail() {
            ArrayList<T> out(((this->size() > 0) ? (this->size()-1) : 0));
            for(int i=1; i<this->size(); i++) out.add(*(this->get(i)));

            return out;
        }

        ArrayList<T> init() {
            ArrayList<T> out(((this->size() > 0) ? (this->size()-1) : 0));
            for(int i=0; i<this->size()-1; i++) out.add(*(this->get(i)));

            return out;
        }

        ArrayList<T> reverse() {
            ArrayList<T> out(this->size());
            for(int i=this->size(); i>0; i--) out.add(*(this->get(i)));

            return out;
        }

        ArrayList<T> take(int n) {
            ArrayList<T> out(n);
            for(int i=0; i<n; i++) out.add(*(this->get(i)));

            return out;
        }

        ArrayList<T> drop(int n) {
            ArrayList<T> out(this->size() - n);
            for(int i=n; i<this->size(); i++) out.add(*(this->get(i)));

            return out;
        }
    };
}

#endif<|endoftext|>


<commit_before>// Copyright (c) 2020 by Robert Bosch GmbH. 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.

#ifndef IOX_POSH_POPO_SAMPLE_INL
#define IOX_POSH_POPO_SAMPLE_INL

namespace iox
{
namespace popo
{
// ============================== Sample<T> ========================= //
template <typename T>
inline Sample<T>::Sample(cxx::unique_ptr<T>&& samplePtr, PublisherInterface<T>& publisher)
    : m_samplePtr(std::move(samplePtr))
    , m_publisherRef(publisher){};

template <typename T>
inline Sample<T>& Sample<T>::operator=(Sample<T>&& rhs)
{
    if (this != &rhs)
    {
        m_publisherRef = rhs.m_publisherRef;
        m_samplePtr = std::move(rhs.m_samplePtr);
        rhs.m_samplePtr = nullptr;
    }
    return *this;
}

template <typename T>
inline Sample<T>::Sample(Sample<T>&& rhs)
    : m_publisherRef(rhs.m_publisherRef) // Need to initialize references in initializer list.
{
    *this = std::move(rhs);
}

template <typename T>
inline Sample<T>::~Sample()
{
    m_samplePtr = nullptr;
}

template <typename T>
inline Sample<T>::Sample(std::nullptr_t) noexcept
{
    m_samplePtr = nullptr; // The pointer will take care of cleaning up resources.
};

template <typename T>
inline T* Sample<T>::operator->() noexcept
{
    return get();
}

template <typename T>
inline T* Sample<T>::get() noexcept
{
    return m_samplePtr.get();
}

template <typename T>
inline mepoo::ChunkHeader* Sample<T>::getHeader() noexcept
{
    return mepoo::convertPayloadPointerToChunkHeader(m_samplePtr.get());
}

template <typename T>
inline void Sample<T>::publish() noexcept
{
    if (m_samplePtr)
    {
        m_publisherRef.get().publish(std::move(*this));
    }

    else
    {
        /// @todo Notify caller of attempt to publish invalid chunk. Or something ?
    }
}

template <typename T>
inline void Sample<T>::release() noexcept
{
    m_samplePtr.release();
}

// ============================== Sample<const T> ========================= //

template <typename T>
inline Sample<const T>::Sample(cxx::unique_ptr<T>&& samplePtr) noexcept
    : m_samplePtr(std::move(samplePtr)){};

template <typename T>
inline Sample<const T>::Sample(std::nullptr_t) noexcept
{
    m_samplePtr = nullptr; // The pointer will take care of cleaning up resources.
};

template <typename T>
inline Sample<const T>& Sample<const T>::operator=(Sample<const T>&& rhs)
{
    if (this != &rhs)
    {
        m_samplePtr = std::move(rhs.m_samplePtr);
        rhs.m_samplePtr = nullptr;
    }
    return *this;
}

template <typename T>
inline Sample<const T>::Sample(Sample<const T>&& rhs)
{
    *this = std::move(rhs);
}

template <typename T>
inline Sample<const T>::~Sample()
{
    m_samplePtr = nullptr;
}

template <typename T>
inline const T* Sample<const T>::operator->() noexcept
{
    return get();
}

template <typename T>
inline const T* Sample<const T>::get() noexcept
{
    return m_samplePtr.get();
}

template <typename T>
inline const mepoo::ChunkHeader* Sample<const T>::getHeader() noexcept
{
    return mepoo::convertPayloadPointerToChunkHeader(m_samplePtr.get());
}

} // namespace popo
} // namespace iox

#endif // IOX_POSH_POPO_SAMPLE_INL
<commit_msg>iox-#252 Fix warnings<commit_after>// Copyright (c) 2020 by Robert Bosch GmbH. 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.

#ifndef IOX_POSH_POPO_SAMPLE_INL
#define IOX_POSH_POPO_SAMPLE_INL

namespace iox
{
namespace popo
{
// ============================== Sample<T> ========================= //
template <typename T>
inline Sample<T>::Sample(cxx::unique_ptr<T>&& samplePtr, PublisherInterface<T>& publisher)
    : m_samplePtr(std::move(samplePtr))
    , m_publisherRef(publisher)
{
}

template <typename T>
inline Sample<T>& Sample<T>::operator=(Sample<T>&& rhs)
{
    if (this != &rhs)
    {
        m_publisherRef = rhs.m_publisherRef;
        m_samplePtr = std::move(rhs.m_samplePtr);
        rhs.m_samplePtr = nullptr;
    }
    return *this;
}

template <typename T>
inline Sample<T>::Sample(Sample<T>&& rhs)
    : m_publisherRef(rhs.m_publisherRef) // Need to initialize references in initializer list.
{
    *this = std::move(rhs);
}

template <typename T>
inline Sample<T>::~Sample()
{
    m_samplePtr = nullptr;
}

template <typename T>
inline Sample<T>::Sample(std::nullptr_t) noexcept
{
    m_samplePtr = nullptr; // The pointer will take care of cleaning up resources.
}

template <typename T>
inline T* Sample<T>::operator->() noexcept
{
    return get();
}

template <typename T>
inline T* Sample<T>::get() noexcept
{
    return m_samplePtr.get();
}

template <typename T>
inline mepoo::ChunkHeader* Sample<T>::getHeader() noexcept
{
    return mepoo::convertPayloadPointerToChunkHeader(m_samplePtr.get());
}

template <typename T>
inline void Sample<T>::publish() noexcept
{
    if (m_samplePtr)
    {
        m_publisherRef.get().publish(std::move(*this));
    }

    else
    {
        /// @todo Notify caller of attempt to publish invalid chunk. Or something ?
    }
}

template <typename T>
inline void Sample<T>::release() noexcept
{
    m_samplePtr.release();
}

// ============================== Sample<const T> ========================= //

template <typename T>
inline Sample<const T>::Sample(cxx::unique_ptr<T>&& samplePtr) noexcept
    : m_samplePtr(std::move(samplePtr))
{
}

template <typename T>
inline Sample<const T>::Sample(std::nullptr_t) noexcept
{
    m_samplePtr = nullptr; // The pointer will take care of cleaning up resources.
}

template <typename T>
inline Sample<const T>& Sample<const T>::operator=(Sample<const T>&& rhs)
{
    if (this != &rhs)
    {
        m_samplePtr = std::move(rhs.m_samplePtr);
        rhs.m_samplePtr = nullptr;
    }
    return *this;
}

template <typename T>
inline Sample<const T>::Sample(Sample<const T>&& rhs)
{
    *this = std::move(rhs);
}

template <typename T>
inline Sample<const T>::~Sample()
{
    m_samplePtr = nullptr;
}

template <typename T>
inline const T* Sample<const T>::operator->() noexcept
{
    return get();
}

template <typename T>
inline const T* Sample<const T>::get() noexcept
{
    return m_samplePtr.get();
}

template <typename T>
inline const mepoo::ChunkHeader* Sample<const T>::getHeader() noexcept
{
    return mepoo::convertPayloadPointerToChunkHeader(m_samplePtr.get());
}

} // namespace popo
} // namespace iox

#endif // IOX_POSH_POPO_SAMPLE_INL
<|endoftext|>


<commit_before>//   Copyright 2015 Patrick Putnam
//
//   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.
#ifndef CLOTHO_ROW_GROUPED_CROSSOVER_METHOD_HPP_
#define CLOTHO_ROW_GROUPED_CROSSOVER_METHOD_HPP_

#include "clotho/data_spaces/crossover/crossover_method_def.hpp"
#include "clotho/data_spaces/association_matrix/row_grouped_association_matrix.hpp"

#include "clotho/data_spaces/generators/crossover_event_generator.hpp"
#include "clotho/utility/bit_helper.hpp"
#include "clotho/utility/debruijn_bit_walker.hpp"

namespace clotho {
namespace genetics {

template < class RNG, class AlleleSpaceType, class BlockType >
class crossover_method< RNG, AlleleSpaceType, association_matrix< BlockType, row_grouped< 2 > > > {
public:
    typedef RNG                                                 random_engine_type;
    typedef AlleleSpaceType                                     allele_type;
    typedef association_matrix< BlockType, row_grouped< 2 > >     sequence_space_type;

    typedef typename sequence_space_type::raw_block_pointer     sequence_iterator;
    typedef typename sequence_space_type::raw_block_pointer     genome_iterator;

    typedef typename allele_type::position_type                 position_type;

    typedef crossover_event_generator< RNG, position_type >     event_generator_type;

    typedef typename sequence_space_type::block_type            block_type;
    typedef clotho::utility::debruijn_bit_walker< block_type >  bit_walker_type;
    typedef clotho::utility::BitHelper< block_type >            bit_helper_type;

    crossover_method( RNG * rng, boost::property_tree::ptree & config ) :
        m_event_gen( rng, config )
    {}

    void initAlleles( allele_type & alls ) {
        m_event_gen.update( alls.position_begin(), alls.position_end() );
    }

    void crossover( genome_iterator start, genome_iterator end, sequence_iterator s, size_t p_step, size_t s_step ) {

        size_t N = m_event_gen.generate();

        if( N != 0 ) {
            size_t j = 0;
            while( start != end ) {
                block_type first = *start++;
                block_type second = *start++;

                block_type hets = first ^ second;
                block_type sec  = bit_helper_type::ALL_UNSET;   // mask state from second strand

                while( hets ) {
                    size_t idx = bit_walker_type::unset_next_index( hets ) + j;

                    if( m_event_gen( idx ) ) {
                        sec |= bit_helper_type::bit_offset( idx );
                    }
                }

                *s = ((first & ~sec) | (second & sec));

                j += bit_helper_type::BITS_PER_BLOCK;

                s += row_grouped< 2 >::GROUP_SIZE;
            }
        } else {
            if( m_event_gen.getBaseSequence() != 0 ) {

                ++start;
                ++end;
            }

            size_t j = 0;
            while( start != end ) {
                *s = *start;

                start += row_grouped< 2 >::GROUP_SIZE;
                s += row_grouped< 2 >::GROUP_SIZE;

                j += bit_helper_type::BITS_PER_BLOCK;
            }
        }
    }

    virtual ~crossover_method() {}

protected:
    event_generator_type m_event_gen;
};

template < class RNG, class AlleleSpaceType, class BlockType >
class crossover_method< RNG, AlleleSpaceType, association_matrix< BlockType, row_grouped< 1 > > > {
public:
    typedef RNG                                                 random_engine_type;
    typedef AlleleSpaceType                                     allele_type;
    typedef association_matrix< BlockType, row_grouped< 2 > >     sequence_space_type;

    typedef typename sequence_space_type::raw_block_pointer     sequence_iterator;
    typedef typename sequence_space_type::raw_block_pointer     genome_iterator;

    typedef typename allele_type::position_type                 position_type;

    typedef crossover_event_generator< RNG, position_type >     event_generator_type;

    typedef typename sequence_space_type::block_type            block_type;
    typedef clotho::utility::debruijn_bit_walker< block_type >  bit_walker_type;
    typedef clotho::utility::BitHelper< block_type >            bit_helper_type;

    crossover_method( RNG * rng, boost::property_tree::ptree & config ) :
        m_event_gen( rng, config )
    {}

    void initAlleles( allele_type & alls ) {
        m_event_gen.update( alls.position_begin(), alls.position_end() );
    }

    void crossover( genome_iterator start, genome_iterator end, sequence_iterator s, size_t p_step, size_t s_step ) {

        size_t N = m_event_gen.generate();

        genome_iterator sec_ptr = end;
        if( N != 0 ) {
            size_t j = 0;
            while( start != end ) {
                block_type first = *start++;
                block_type second = *sec_ptr++;

                block_type hets = first ^ second;
                block_type sec  = bit_helper_type::ALL_UNSET;   // mask state from second strand

                while( hets ) {
                    size_t idx = bit_walker_type::unset_next_index( hets ) + j;

                    if( m_event_gen( idx ) ) {
                        sec |= bit_helper_type::bit_offset( idx );
                    }
                }

                *s++ = ((first & ~sec) | (second & sec));

                j += bit_helper_type::BITS_PER_BLOCK;
            }
        } else {
            size_t N = (end - start);

            if( m_event_gen.getBaseSequence() != 0 ) {
                // use second strand
                start = end;
            }

            while( N-- ) {
                *s++ = *start++;
            }
        }
    }

    virtual ~crossover_method() {}

protected:
    event_generator_type m_event_gen;
};
}   // namespace genetics
}   // namespace clotho

#endif  // CLOTHO_ROW_GROUPED_CROSSOVER_METHOD_HPP_
<commit_msg>Unrolling copy<commit_after>//   Copyright 2015 Patrick Putnam
//
//   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.
#ifndef CLOTHO_ROW_GROUPED_CROSSOVER_METHOD_HPP_
#define CLOTHO_ROW_GROUPED_CROSSOVER_METHOD_HPP_

#include "clotho/data_spaces/crossover/crossover_method_def.hpp"
#include "clotho/data_spaces/association_matrix/row_grouped_association_matrix.hpp"

#include "clotho/data_spaces/generators/crossover_event_generator.hpp"
#include "clotho/utility/bit_helper.hpp"
#include "clotho/utility/debruijn_bit_walker.hpp"

namespace clotho {
namespace genetics {

template < class RNG, class AlleleSpaceType, class BlockType >
class crossover_method< RNG, AlleleSpaceType, association_matrix< BlockType, row_grouped< 2 > > > {
public:
    typedef RNG                                                 random_engine_type;
    typedef AlleleSpaceType                                     allele_type;
    typedef association_matrix< BlockType, row_grouped< 2 > >     sequence_space_type;

    typedef typename sequence_space_type::raw_block_pointer     sequence_iterator;
    typedef typename sequence_space_type::raw_block_pointer     genome_iterator;

    typedef typename allele_type::position_type                 position_type;

    typedef crossover_event_generator< RNG, position_type >     event_generator_type;

    typedef typename sequence_space_type::block_type            block_type;
    typedef clotho::utility::debruijn_bit_walker< block_type >  bit_walker_type;
    typedef clotho::utility::BitHelper< block_type >            bit_helper_type;

    crossover_method( RNG * rng, boost::property_tree::ptree & config ) :
        m_event_gen( rng, config )
    {}

    void initAlleles( allele_type & alls ) {
        m_event_gen.update( alls.position_begin(), alls.position_end() );
    }

    void crossover( genome_iterator start, genome_iterator end, sequence_iterator s, size_t p_step, size_t s_step ) {

        size_t N = m_event_gen.generate();

        if( N != 0 ) {
            size_t j = 0;
            while( start != end ) {
                block_type first = *start++;
                block_type second = *start++;

                block_type hets = first ^ second;
                block_type sec  = bit_helper_type::ALL_UNSET;   // mask state from second strand

                while( hets ) {
                    size_t idx = bit_walker_type::unset_next_index( hets ) + j;

                    if( m_event_gen( idx ) ) {
                        sec |= bit_helper_type::bit_offset( idx );
                    }
                }

                *s = ((first & ~sec) | (second & sec));

                j += bit_helper_type::BITS_PER_BLOCK;

                s += row_grouped< 2 >::GROUP_SIZE;
            }
        } else {
            if( m_event_gen.getBaseSequence() != 0 ) {

                ++start;
                ++end;
            }

            size_t j = 0;
            while( start != end ) {
                *s = *start;

                start += row_grouped< 2 >::GROUP_SIZE;
                s += row_grouped< 2 >::GROUP_SIZE;

                j += bit_helper_type::BITS_PER_BLOCK;
            }
        }
    }

    virtual ~crossover_method() {}

protected:
    event_generator_type m_event_gen;
};

template < class RNG, class AlleleSpaceType, class BlockType >
class crossover_method< RNG, AlleleSpaceType, association_matrix< BlockType, row_grouped< 1 > > > {
public:
    typedef RNG                                                 random_engine_type;
    typedef AlleleSpaceType                                     allele_type;
    typedef association_matrix< BlockType, row_grouped< 2 > >     sequence_space_type;

    typedef typename sequence_space_type::raw_block_pointer     sequence_iterator;
    typedef typename sequence_space_type::raw_block_pointer     genome_iterator;

    typedef typename allele_type::position_type                 position_type;

    typedef crossover_event_generator< RNG, position_type >     event_generator_type;

    typedef typename sequence_space_type::block_type            block_type;
    typedef clotho::utility::debruijn_bit_walker< block_type >  bit_walker_type;
    typedef clotho::utility::BitHelper< block_type >            bit_helper_type;

    crossover_method( RNG * rng, boost::property_tree::ptree & config ) :
        m_event_gen( rng, config )
    {}

    void initAlleles( allele_type & alls ) {
        m_event_gen.update( alls.position_begin(), alls.position_end() );
    }

    void crossover( genome_iterator start, genome_iterator end, sequence_iterator s, size_t p_step, size_t s_step ) {

        size_t N = m_event_gen.generate();

        genome_iterator sec_ptr = end;
        if( N != 0 ) {
            size_t j = 0;
            while( start != end ) {
                block_type first = *start++;
                block_type second = *sec_ptr++;

                block_type hets = first ^ second;
                block_type sec  = bit_helper_type::ALL_UNSET;   // mask state from second strand

                while( hets ) {
                    size_t idx = bit_walker_type::unset_next_index( hets ) + j;

                    if( m_event_gen( idx ) ) {
                        sec |= bit_helper_type::bit_offset( idx );
                    }
                }

                *s++ = ((first & ~sec) | (second & sec));

                j += bit_helper_type::BITS_PER_BLOCK;
            }
        } else {
            size_t N = (end - start);

            if( m_event_gen.getBaseSequence() != 0 ) {
                // use second strand
                start = end;
            }

            size_t M = N % 4;
            N -= M;
            while( M-- ) {
                *s++ = *start++;
            }

            while( N ) {
                *s++ = *start++;
                *s++ = *start++;
                *s++ = *start++;
                *s++ = *start++;
                N -= 4;
            }
        }
    }

    virtual ~crossover_method() {}

protected:
    event_generator_type m_event_gen;
};
}   // namespace genetics
}   // namespace clotho

#endif  // CLOTHO_ROW_GROUPED_CROSSOVER_METHOD_HPP_
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * 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.
 */

#include "perfetto/ext/base/utils.h"

#include <string>

#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/string_utils.h"

#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
    PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) ||   \
    PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
#include <limits.h>
#include <stdlib.h>  // For _exit()
#include <unistd.h>  // For getpagesize() and geteuid() & fork()
#endif

#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
#include <mach-o/dyld.h>
#include <mach/vm_page_size.h>
#endif

#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include <Windows.h>
#include <io.h>
#include <malloc.h>  // For _aligned_malloc().
#endif

#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
#include <dlfcn.h>
#include <malloc.h>

#ifdef M_PURGE
#define PERFETTO_M_PURGE M_PURGE
#else
// Only available in in-tree builds and on newer SDKs.
#define PERFETTO_M_PURGE -101
#endif  // M_PURGE

namespace {
extern "C" {
using MalloptType = void (*)(int, int);
}
}  // namespace
#endif  // OS_ANDROID

namespace {

#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)

// Preserve the %rbx register via %rdi to work around a clang bug
// https://bugs.llvm.org/show_bug.cgi?id=17907 (%rbx in an output constraint
// is not considered a clobbered register).
#define PERFETTO_GETCPUID(a, b, c, d, a_inp, c_inp) \
  asm("mov %%rbx, %%rdi\n"                          \
      "cpuid\n"                                     \
      "xchg %%rdi, %%rbx\n"                         \
      : "=a"(a), "=D"(b), "=c"(c), "=d"(d)          \
      : "a"(a_inp), "2"(c_inp))

uint32_t GetXCR0EAX() {
  uint32_t eax = 0, edx = 0;
  asm("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));
  return eax;
}

// If we are building with -msse4 check that the CPU actually supports it.
// This file must be kept in sync with gn/standalone/BUILD.gn.
void PERFETTO_EXPORT_COMPONENT __attribute__((constructor))
CheckCpuOptimizations() {
  uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
  PERFETTO_GETCPUID(eax, ebx, ecx, edx, 1, 0);

  static constexpr uint64_t xcr0_xmm_mask = 0x2;
  static constexpr uint64_t xcr0_ymm_mask = 0x4;
  static constexpr uint64_t xcr0_avx_mask = xcr0_xmm_mask | xcr0_ymm_mask;

  const bool have_popcnt = ecx & (1u << 23);
  const bool have_sse4_2 = ecx & (1u << 20);
  const bool have_avx =
      // Does the OS save/restore XMM and YMM state?
      (ecx & (1u << 27)) &&  // OS support XGETBV.
      (ecx & (1u << 28)) &&  // AVX supported in hardware
      ((GetXCR0EAX() & xcr0_avx_mask) == xcr0_avx_mask);

  // Get level 7 features (eax = 7 and ecx= 0), to check for AVX2 support.
  // (See Intel 64 and IA-32 Architectures Software Developer's Manual
  //  Volume 2A: Instruction Set Reference, A-M CPUID).
  PERFETTO_GETCPUID(eax, ebx, ecx, edx, 7, 0);
  const bool have_avx2 = have_avx && ((ebx >> 5) & 0x1);
  const bool have_bmi = (ebx >> 3) & 0x1;
  const bool have_bmi2 = (ebx >> 8) & 0x1;

  if (!have_sse4_2 || !have_popcnt || !have_avx2 || !have_bmi || !have_bmi2) {
    fprintf(
        stderr,
        "This executable requires a x86_64 cpu that supports SSE4.2, BMI2 and "
        "AVX2.\n"
#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
        "On MacOS, this might be caused by running x86_64 binaries on arm64.\n"
        "See https://github.com/google/perfetto/issues/294 for more.\n"
#endif
        "Rebuild with enable_perfetto_x64_cpu_opt=false.\n");
    _exit(126);
  }
}
#endif

}  // namespace

namespace perfetto {
namespace base {

void MaybeReleaseAllocatorMemToOS() {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
  // mallopt() on Android requires SDK level 26. Many targets and embedders
  // still depend on a lower SDK level. Given mallopt() is a quite simple API,
  // use reflection to do this rather than bumping the SDK level for all
  // embedders. This keeps the behavior of standalone builds aligned with
  // in-tree builds.
  static MalloptType mallopt_fn =
      reinterpret_cast<MalloptType>(dlsym(RTLD_DEFAULT, "mallopt"));
  if (!mallopt_fn)
    return;
  mallopt_fn(PERFETTO_M_PURGE, 0);
#endif
}

uint32_t GetSysPageSize() {
  ignore_result(kPageSize);  // Just to keep the amalgamated build happy.
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
  static std::atomic<uint32_t> page_size{0};
  // This function might be called in hot paths. Avoid calling getpagesize() all
  // the times, in many implementations getpagesize() calls sysconf() which is
  // not cheap.
  uint32_t cached_value = page_size.load(std::memory_order_relaxed);
  if (PERFETTO_UNLIKELY(cached_value == 0)) {
    cached_value = static_cast<uint32_t>(getpagesize());
    page_size.store(cached_value, std::memory_order_relaxed);
  }
  return cached_value;
#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
  return static_cast<uint32_t>(vm_page_size);
#else
  return 4096;
#endif
}

uid_t GetCurrentUserId() {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
    PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
  return geteuid();
#else
  // TODO(primiano): On Windows we could hash the current user SID and derive a
  // numeric user id [1]. It is not clear whether we need that. Right now that
  // would not bring any benefit. Returning 0 unil we can prove we need it.
  // [1]:https://android-review.googlesource.com/c/platform/external/perfetto/+/1513879/25/src/base/utils.cc
  return 0;
#endif
}

void SetEnv(const std::string& key, const std::string& value) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  PERFETTO_CHECK(::_putenv_s(key.c_str(), value.c_str()) == 0);
#else
  PERFETTO_CHECK(::setenv(key.c_str(), value.c_str(), /*overwrite=*/true) == 0);
#endif
}

void Daemonize(std::function<int()> parent_cb) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
    PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
  pid_t pid;
  switch (pid = fork()) {
    case -1:
      PERFETTO_FATAL("fork");
    case 0: {
      PERFETTO_CHECK(setsid() != -1);
      base::ignore_result(chdir("/"));
      base::ScopedFile null = base::OpenFile("/dev/null", O_RDONLY);
      PERFETTO_CHECK(null);
      PERFETTO_CHECK(dup2(*null, STDIN_FILENO) != -1);
      PERFETTO_CHECK(dup2(*null, STDOUT_FILENO) != -1);
      PERFETTO_CHECK(dup2(*null, STDERR_FILENO) != -1);
      // Do not accidentally close stdin/stdout/stderr.
      if (*null <= 2)
        null.release();
      break;
    }
    default:
      printf("%d\n", pid);
      int err = parent_cb();
      exit(err);
  }
#else
  // Avoid -Wunreachable warnings.
  if (reinterpret_cast<intptr_t>(&Daemonize) != 16)
    PERFETTO_FATAL("--background is only supported on Linux/Android/Mac");
  ignore_result(parent_cb);
#endif  // OS_WIN
}

std::string GetCurExecutablePath() {
  std::string self_path;
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
    PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
  char buf[PATH_MAX];
  ssize_t size = readlink("/proc/self/exe", buf, sizeof(buf));
  PERFETTO_CHECK(size != -1);
  // readlink does not null terminate.
  self_path = std::string(buf, static_cast<size_t>(size));
#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
  uint32_t size = 0;
  PERFETTO_CHECK(_NSGetExecutablePath(nullptr, &size));
  self_path.resize(size);
  PERFETTO_CHECK(_NSGetExecutablePath(&self_path[0], &size) == 0);
#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  char buf[MAX_PATH];
  auto len = ::GetModuleFileNameA(nullptr /*current*/, buf, sizeof(buf));
  self_path = std::string(buf, len);
#else
  PERFETTO_FATAL(
      "GetCurExecutableDir() not implemented on the current platform");
#endif
  return self_path;
}

std::string GetCurExecutableDir() {
  auto path = GetCurExecutablePath();
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  // Paths in Windows can have both kinds of slashes (mingw vs msvc).
  path = path.substr(0, path.find_last_of('\\'));
#endif
  path = path.substr(0, path.find_last_of('/'));
  return path;
}

void* AlignedAlloc(size_t alignment, size_t size) {
  void* res = nullptr;
  alignment = AlignUp<sizeof(void*)>(alignment);  // At least pointer size.
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  // Window's _aligned_malloc() has a nearly identically signature to Unix's
  // aligned_alloc() but its arguments are obviously swapped.
  res = _aligned_malloc(size, alignment);
#else
  // aligned_alloc() has been introduced in Android only in API 28.
  // Also NaCl and Fuchsia seems to have only posix_memalign().
  ignore_result(posix_memalign(&res, alignment, size));
#endif
  PERFETTO_CHECK(res);
  return res;
}

void AlignedFree(void* ptr) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  _aligned_free(ptr);  // MSDN says it is fine to pass nullptr.
#else
  free(ptr);
#endif
}

std::string HexDump(const void* data_void, size_t len, size_t bytes_per_line) {
  const char* data = reinterpret_cast<const char*>(data_void);
  std::string res;
  static const size_t kPadding = bytes_per_line * 3 + 12;
  std::unique_ptr<char[]> line(new char[bytes_per_line * 4 + 128]);
  for (size_t i = 0; i < len; i += bytes_per_line) {
    char* wptr = line.get();
    wptr += base::SprintfTrunc(wptr, 19, "%08zX: ", i);
    for (size_t j = i; j < i + bytes_per_line && j < len; j++) {
      wptr += base::SprintfTrunc(wptr, 4, "%02X ",
                                 static_cast<unsigned>(data[j]) & 0xFF);
    }
    for (size_t j = static_cast<size_t>(wptr - line.get()); j < kPadding; ++j)
      *(wptr++) = ' ';
    for (size_t j = i; j < i + bytes_per_line && j < len; j++) {
      char c = data[j];
      *(wptr++) = (c >= 32 && c < 127) ? c : '.';
    }
    *(wptr++) = '\n';
    *(wptr++) = '\0';
    res.append(line.get());
  }
  return res;
}

}  // namespace base
}  // namespace perfetto
<commit_msg>base::Daemonize(): wait for child setsid()<commit_after>/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * 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.
 */

#include "perfetto/ext/base/utils.h"

#include <string>

#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/pipe.h"
#include "perfetto/ext/base/string_utils.h"

#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
    PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) ||   \
    PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
#include <limits.h>
#include <stdlib.h>  // For _exit()
#include <unistd.h>  // For getpagesize() and geteuid() & fork()
#endif

#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
#include <mach-o/dyld.h>
#include <mach/vm_page_size.h>
#endif

#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
#include <Windows.h>
#include <io.h>
#include <malloc.h>  // For _aligned_malloc().
#endif

#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
#include <dlfcn.h>
#include <malloc.h>

#ifdef M_PURGE
#define PERFETTO_M_PURGE M_PURGE
#else
// Only available in in-tree builds and on newer SDKs.
#define PERFETTO_M_PURGE -101
#endif  // M_PURGE

namespace {
extern "C" {
using MalloptType = void (*)(int, int);
}
}  // namespace
#endif  // OS_ANDROID

namespace {

#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)

// Preserve the %rbx register via %rdi to work around a clang bug
// https://bugs.llvm.org/show_bug.cgi?id=17907 (%rbx in an output constraint
// is not considered a clobbered register).
#define PERFETTO_GETCPUID(a, b, c, d, a_inp, c_inp) \
  asm("mov %%rbx, %%rdi\n"                          \
      "cpuid\n"                                     \
      "xchg %%rdi, %%rbx\n"                         \
      : "=a"(a), "=D"(b), "=c"(c), "=d"(d)          \
      : "a"(a_inp), "2"(c_inp))

uint32_t GetXCR0EAX() {
  uint32_t eax = 0, edx = 0;
  asm("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));
  return eax;
}

// If we are building with -msse4 check that the CPU actually supports it.
// This file must be kept in sync with gn/standalone/BUILD.gn.
void PERFETTO_EXPORT_COMPONENT __attribute__((constructor))
CheckCpuOptimizations() {
  uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
  PERFETTO_GETCPUID(eax, ebx, ecx, edx, 1, 0);

  static constexpr uint64_t xcr0_xmm_mask = 0x2;
  static constexpr uint64_t xcr0_ymm_mask = 0x4;
  static constexpr uint64_t xcr0_avx_mask = xcr0_xmm_mask | xcr0_ymm_mask;

  const bool have_popcnt = ecx & (1u << 23);
  const bool have_sse4_2 = ecx & (1u << 20);
  const bool have_avx =
      // Does the OS save/restore XMM and YMM state?
      (ecx & (1u << 27)) &&  // OS support XGETBV.
      (ecx & (1u << 28)) &&  // AVX supported in hardware
      ((GetXCR0EAX() & xcr0_avx_mask) == xcr0_avx_mask);

  // Get level 7 features (eax = 7 and ecx= 0), to check for AVX2 support.
  // (See Intel 64 and IA-32 Architectures Software Developer's Manual
  //  Volume 2A: Instruction Set Reference, A-M CPUID).
  PERFETTO_GETCPUID(eax, ebx, ecx, edx, 7, 0);
  const bool have_avx2 = have_avx && ((ebx >> 5) & 0x1);
  const bool have_bmi = (ebx >> 3) & 0x1;
  const bool have_bmi2 = (ebx >> 8) & 0x1;

  if (!have_sse4_2 || !have_popcnt || !have_avx2 || !have_bmi || !have_bmi2) {
    fprintf(
        stderr,
        "This executable requires a x86_64 cpu that supports SSE4.2, BMI2 and "
        "AVX2.\n"
#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
        "On MacOS, this might be caused by running x86_64 binaries on arm64.\n"
        "See https://github.com/google/perfetto/issues/294 for more.\n"
#endif
        "Rebuild with enable_perfetto_x64_cpu_opt=false.\n");
    _exit(126);
  }
}
#endif

}  // namespace

namespace perfetto {
namespace base {

void MaybeReleaseAllocatorMemToOS() {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
  // mallopt() on Android requires SDK level 26. Many targets and embedders
  // still depend on a lower SDK level. Given mallopt() is a quite simple API,
  // use reflection to do this rather than bumping the SDK level for all
  // embedders. This keeps the behavior of standalone builds aligned with
  // in-tree builds.
  static MalloptType mallopt_fn =
      reinterpret_cast<MalloptType>(dlsym(RTLD_DEFAULT, "mallopt"));
  if (!mallopt_fn)
    return;
  mallopt_fn(PERFETTO_M_PURGE, 0);
#endif
}

uint32_t GetSysPageSize() {
  ignore_result(kPageSize);  // Just to keep the amalgamated build happy.
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
  static std::atomic<uint32_t> page_size{0};
  // This function might be called in hot paths. Avoid calling getpagesize() all
  // the times, in many implementations getpagesize() calls sysconf() which is
  // not cheap.
  uint32_t cached_value = page_size.load(std::memory_order_relaxed);
  if (PERFETTO_UNLIKELY(cached_value == 0)) {
    cached_value = static_cast<uint32_t>(getpagesize());
    page_size.store(cached_value, std::memory_order_relaxed);
  }
  return cached_value;
#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
  return static_cast<uint32_t>(vm_page_size);
#else
  return 4096;
#endif
}

uid_t GetCurrentUserId() {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
    PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
  return geteuid();
#else
  // TODO(primiano): On Windows we could hash the current user SID and derive a
  // numeric user id [1]. It is not clear whether we need that. Right now that
  // would not bring any benefit. Returning 0 unil we can prove we need it.
  // [1]:https://android-review.googlesource.com/c/platform/external/perfetto/+/1513879/25/src/base/utils.cc
  return 0;
#endif
}

void SetEnv(const std::string& key, const std::string& value) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  PERFETTO_CHECK(::_putenv_s(key.c_str(), value.c_str()) == 0);
#else
  PERFETTO_CHECK(::setenv(key.c_str(), value.c_str(), /*overwrite=*/true) == 0);
#endif
}

void Daemonize(std::function<int()> parent_cb) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
    PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
  Pipe pipe = Pipe::Create(Pipe::kBothBlock);
  pid_t pid;
  switch (pid = fork()) {
    case -1:
      PERFETTO_FATAL("fork");
    case 0: {
      PERFETTO_CHECK(setsid() != -1);
      base::ignore_result(chdir("/"));
      base::ScopedFile null = base::OpenFile("/dev/null", O_RDONLY);
      PERFETTO_CHECK(null);
      PERFETTO_CHECK(dup2(*null, STDIN_FILENO) != -1);
      PERFETTO_CHECK(dup2(*null, STDOUT_FILENO) != -1);
      PERFETTO_CHECK(dup2(*null, STDERR_FILENO) != -1);
      // Do not accidentally close stdin/stdout/stderr.
      if (*null <= 2)
        null.release();
      WriteAll(*pipe.wr, "1", 1);
      break;
    }
    default: {
      // Wait for the child process to have reached the setsid() call. This is
      // to avoid that 'adb shell perfetto -D' destroys the terminal (hence
      // sending a SIGHUP to the child) before the child has detached from the
      // terminal (see b/238644870).

      // This is to unblock the read() below (with EOF, which will fail the
      // CHECK) in the unlikely case of the child crashing before WriteAll("1").
      pipe.wr.reset();
      char one = '\0';
      PERFETTO_CHECK(Read(*pipe.rd, &one, sizeof(one)) == 1 && one == '1');
      printf("%d\n", pid);
      int err = parent_cb();
      exit(err);
    }
  }
#else
  // Avoid -Wunreachable warnings.
  if (reinterpret_cast<intptr_t>(&Daemonize) != 16)
    PERFETTO_FATAL("--background is only supported on Linux/Android/Mac");
  ignore_result(parent_cb);
#endif  // OS_WIN
}

std::string GetCurExecutablePath() {
  std::string self_path;
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
    PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
    PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
  char buf[PATH_MAX];
  ssize_t size = readlink("/proc/self/exe", buf, sizeof(buf));
  PERFETTO_CHECK(size != -1);
  // readlink does not null terminate.
  self_path = std::string(buf, static_cast<size_t>(size));
#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
  uint32_t size = 0;
  PERFETTO_CHECK(_NSGetExecutablePath(nullptr, &size));
  self_path.resize(size);
  PERFETTO_CHECK(_NSGetExecutablePath(&self_path[0], &size) == 0);
#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  char buf[MAX_PATH];
  auto len = ::GetModuleFileNameA(nullptr /*current*/, buf, sizeof(buf));
  self_path = std::string(buf, len);
#else
  PERFETTO_FATAL(
      "GetCurExecutableDir() not implemented on the current platform");
#endif
  return self_path;
}

std::string GetCurExecutableDir() {
  auto path = GetCurExecutablePath();
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  // Paths in Windows can have both kinds of slashes (mingw vs msvc).
  path = path.substr(0, path.find_last_of('\\'));
#endif
  path = path.substr(0, path.find_last_of('/'));
  return path;
}

void* AlignedAlloc(size_t alignment, size_t size) {
  void* res = nullptr;
  alignment = AlignUp<sizeof(void*)>(alignment);  // At least pointer size.
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  // Window's _aligned_malloc() has a nearly identically signature to Unix's
  // aligned_alloc() but its arguments are obviously swapped.
  res = _aligned_malloc(size, alignment);
#else
  // aligned_alloc() has been introduced in Android only in API 28.
  // Also NaCl and Fuchsia seems to have only posix_memalign().
  ignore_result(posix_memalign(&res, alignment, size));
#endif
  PERFETTO_CHECK(res);
  return res;
}

void AlignedFree(void* ptr) {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
  _aligned_free(ptr);  // MSDN says it is fine to pass nullptr.
#else
  free(ptr);
#endif
}

std::string HexDump(const void* data_void, size_t len, size_t bytes_per_line) {
  const char* data = reinterpret_cast<const char*>(data_void);
  std::string res;
  static const size_t kPadding = bytes_per_line * 3 + 12;
  std::unique_ptr<char[]> line(new char[bytes_per_line * 4 + 128]);
  for (size_t i = 0; i < len; i += bytes_per_line) {
    char* wptr = line.get();
    wptr += base::SprintfTrunc(wptr, 19, "%08zX: ", i);
    for (size_t j = i; j < i + bytes_per_line && j < len; j++) {
      wptr += base::SprintfTrunc(wptr, 4, "%02X ",
                                 static_cast<unsigned>(data[j]) & 0xFF);
    }
    for (size_t j = static_cast<size_t>(wptr - line.get()); j < kPadding; ++j)
      *(wptr++) = ' ';
    for (size_t j = i; j < i + bytes_per_line && j < len; j++) {
      char c = data[j];
      *(wptr++) = (c >= 32 && c < 127) ? c : '.';
    }
    *(wptr++) = '\n';
    *(wptr++) = '\0';
    res.append(line.get());
  }
  return res;
}

}  // namespace base
}  // namespace perfetto
<|endoftext|>


<commit_before>/*
 * benchmark.cpp
 *
 *  Created on: Jun 23, 2015
 *      Author: Fabian Tschopp
 */

#include "benchmark.hpp"
#include <vector>
#include <string>
#include <iostream>
#include <functional>
#include <chrono>
#include <cassert>
#include "../include/filesystem_utils.hpp"

namespace caffe_neural {

void FillNet(shared_ptr<Layer<float>> data_layer,
             shared_ptr<Layer<float>> label_layer, int num_output) {

  std::function<float()> rfu = GetRandomUniform<float>(-1.0, 1.0);
  std::function<float()> riu = GetRandomUniform(0, num_output);

  if (data_layer != NULL) {
    std::vector<cv::Mat> images;
    std::vector<int> labels;

    shared_ptr<caffe::MemoryDataLayer<float>> data_layer_ptr =
        boost::dynamic_pointer_cast<caffe::MemoryDataLayer<float>>(data_layer);

    // int bn = data_layer_ptr->batch_size();
    int bc = data_layer_ptr->channels();
    int bh = data_layer_ptr->height();
    int bw = data_layer_ptr->width();

    cv::Mat image(bh, bw, CV_32FC(bc));

#pragma omp parallel for
    for (int h = 0; h < bh; ++h) {
      for (int w = 0; w < bw; ++w) {
        for (int c = 0; c < bc; ++c) {
          *(image.ptr<float>(h, w) + c) = rfu();
        }
      }
    }

    images.push_back(image);
    labels.push_back(0);
    data_layer_ptr->AddMatVector(images, labels);

  }

  if (label_layer != NULL) {
    std::vector<cv::Mat> images;
    std::vector<int> labels;

    shared_ptr<caffe::MemoryDataLayer<float>> layer_ptr =
        boost::dynamic_pointer_cast<caffe::MemoryDataLayer<float>>(label_layer);

    // int bn = layer_ptr->batch_size();
    int bc = layer_ptr->channels();
    int bh = layer_ptr->height();
    int bw = layer_ptr->width();

    cv::Mat image(bh, bw, CV_32FC(bc));

#pragma omp parallel for
    for (int h = 0; h < bh; ++h) {
      for (int w = 0; w < bw; ++w) {
        for (int c = 0; c < bc; ++c) {
          *(image.ptr<float>(h, w) + c) = riu();
        }
      }
    }

    images.push_back(image);
    labels.push_back(0);
    layer_ptr->AddMatVector(images, labels);
  }
}

int Benchmark(caffe_neural::ToolParam &tool_param, CommonSettings &settings) {

  BenchmarkParam benchmark_param = tool_param.benchmark(settings.param_index);
  TrainParam train_param = tool_param.train(
      benchmark_param.has_train_index() ? benchmark_param.train_index() : 0);
  ProcessParam process_param = tool_param.process(
      benchmark_param.has_process_index() ?
          benchmark_param.process_index() : 0);

  int warmup_runs =
      benchmark_param.has_warmup_runs() ? benchmark_param.warmup_runs() : 0;
  int bench_runs =
      benchmark_param.has_bench_runs() ? benchmark_param.bench_runs() : 1;

  if (!benchmark_param.has_output()) {
    LOG(FATAL)<< "Missing output path for benchmarking.";

  }

  // Create output directories
  bofs::path benchpath(benchmark_param.output());
  bofs::create_directories(benchpath);

  std::string proto_solver = train_param.solver();
  std::string process_net = process_param.process_net();

  std::chrono::time_point<std::chrono::high_resolution_clock> t_start, t_end;

  // Benchmark block 1: Training Net
  if (benchmark_param.has_train_index()) {
    caffe::SolverParameter solver_param;
    caffe::ReadProtoFromTextFileOrDie(proto_solver, &solver_param);
    shared_ptr<caffe::Solver<float> > solver(
        caffe::GetSolver<float>(solver_param));
    boost::shared_ptr<caffe::Net<float>> net = solver->net();

    std::vector<double> layer_forward_times(net->layers().size());
    std::vector<double> layer_backward_times(net->layers().size());

    double total_forward_time = 0;
    double total_backward_time = 0;

    for (int run = 0; run < warmup_runs + bench_runs; ++run) {
      FillNet(net->layers()[1], net->layers()[0], train_param.input().labels());

      // Benchmark 1: Layer wise measurements (forward)
      for (int l = 0; l < net->layers().size(); ++l) {
        t_start = std::chrono::high_resolution_clock::now();
        net->ForwardFromTo(l, l);
        Caffe::Synchronize(net->layers()[l]->device_context()->id());
        t_end = std::chrono::high_resolution_clock::now();
        if (run >= warmup_runs) {
          layer_forward_times[l] += (t_end - t_start).count();
        }
      }

      // Benchmark 2: Layer wise measurements (backward)
      for (int l = net->layers().size() - 1; l >= 0; --l) {
        t_start = std::chrono::high_resolution_clock::now();
        net->BackwardFromTo(l, l);
        Caffe::Synchronize(net->layers()[l]->device_context()->id());
        t_end = std::chrono::high_resolution_clock::now();
        if (run >= warmup_runs) {
          layer_backward_times[l] += (t_end - t_start).count();
        }
      }
    }

    for (int run = 0; run < warmup_runs + bench_runs; ++run) {
      FillNet(net->layers()[1], net->layers()[0], train_param.input().labels());

      // Benchmark 3: Whole forward pass
      t_start = std::chrono::high_resolution_clock::now();
      net->ForwardPrefilled();
      Caffe::Synchronize(
          net->layers()[net->layers().size() - 1]->device_context()->id());
      t_end = std::chrono::high_resolution_clock::now();
      LOG(INFO) << "Forward pass: " << std::setprecision(10)
          << (double)((t_end - t_start).count())/((double)1e6) << " ms";
      if (run >= warmup_runs) {
        total_forward_time += (t_end - t_start).count();
      }

      // Benchmark 4: Whole backward pass
      t_start = std::chrono::high_resolution_clock::now();
      net->Backward();
      Caffe::Synchronize(net->layers()[0]->device_context()->id());
      t_end = std::chrono::high_resolution_clock::now();
      LOG(INFO) << "Backward pass: " << std::setprecision(10)
          << (double)((t_end - t_start).count())/((double)1e6) << " ms";
      if (run >= warmup_runs) {
        total_backward_time += (t_end - t_start).count();
      }
    }

    // Write outputs
    std::vector<std::string> layers = net->layer_names();

    {
      bofs::path filep = benchpath;
      filep /= ("/train_forward_layers_timings.csv");

      std::ofstream out_file;
      out_file.open(filep.string());
      assert(out_file.is_open());
      for (int l = 0; l < net->layers().size(); ++l) {
        out_file << l << ";" << layers[l] << ";"
                 << std::setprecision(10)
                 << layer_forward_times[l] / ((double) bench_runs * 1e6)
                 << std::endl;
      }
      out_file.close();
    }

    {
      bofs::path filep = benchpath;
      filep /= ("/train_backward_layers_timings.csv");

      std::ofstream out_file;
      out_file.open(filep.string());
      assert(out_file.is_open());
      for (int l = 0; l < net->layers().size(); ++l) {
        out_file << l << ";" << layers[l] << ";"
                 << std::setprecision(10)
                 << layer_backward_times[l] / ((double) bench_runs * 1e6)
                 << std::endl;
      }
      out_file.close();
    }

    {
      bofs::path filep = benchpath;
      filep /= ("/train_total_timings.csv");

      std::ofstream out_file;
      out_file.open(filep.string());
      assert(out_file.is_open());

      out_file << "Forward;" << std::setprecision(10)
               << total_forward_time / ((double) bench_runs * 1e6)
               << std::endl;

      out_file << "Backward;" << std::setprecision(10)
               << total_backward_time / ((double) bench_runs * 1e6)
               << std::endl;
      out_file.close();
    }

    {
      bofs::path filep = benchpath;
      filep /= ("/train_memory_usage.csv");

      std::ofstream out_file;
      out_file.open(filep.string());
      assert(out_file.is_open());

      out_file << "Peak memory usage;"
          << net->layers()[0]->device_context()->peak_memory_usage()
          << std::endl;
      out_file.close();
    }

  }

  // Benchmark block 2: Processing Net
  if (benchmark_param.has_process_index()) {
    Net<float> net(process_net, caffe::TEST);

    std::vector<double> layer_forward_times(net.layers().size());
    double total_forward_time = 0;

    // Benchmark 1: Layer wise measurements (forward)
    for (int run = 0; run < warmup_runs + bench_runs; ++run) {
      FillNet(net.layers()[0], NULL, train_param.input().labels());

      // Benchmark 1: Layer wise measurements (forward)
      for (int l = 0; l < net.layers().size(); ++l) {
        t_start = std::chrono::high_resolution_clock::now();
        net.ForwardFromTo(l, l);
        Caffe::Synchronize(net.layers()[l]->device_context()->id());
        t_end = std::chrono::high_resolution_clock::now();
        if (run >= warmup_runs) {
          layer_forward_times[l] += (t_end - t_start).count();
        }
      }
    }

    // Benchmark 2: Whole forward pass
    for (int run = 0; run < warmup_runs + bench_runs; ++run) {
      FillNet(net.layers()[0], NULL, train_param.input().labels());
      t_start = std::chrono::high_resolution_clock::now();
      net.ForwardPrefilled();
      Caffe::Synchronize(
          net.layers()[net.layers().size() - 1]->device_context()->id());
      t_end = std::chrono::high_resolution_clock::now();
      LOG(INFO) << "Forward pass: " << std::setprecision(10)
          << (double)((t_end - t_start).count())/((double)1e6) << " ms";
      if (run >= warmup_runs) {
        total_forward_time += (t_end - t_start).count();
      }
    }

    // Write outputs
    std::vector<std::string> layers = net.layer_names();

    {
      bofs::path filep = benchpath;
      filep /= ("/process_forward_layers_timings.csv");

      std::ofstream out_file;
      out_file.open(filep.string());
      assert(out_file.is_open());
      for (int l = 0; l < net.layers().size(); ++l) {
        out_file << l << ";" << layers[l] << ";"
                 << std::setprecision(10)
                 << layer_forward_times[l] / ((double) bench_runs * 1e6)
                 << std::endl;
      }
      out_file.close();
    }

    {
      bofs::path filep = benchpath;
      filep /= ("/process_total_timings.csv");

      std::ofstream out_file;
      out_file.open(filep.string());
      assert(out_file.is_open());

      out_file << "Forward;" << std::setprecision(10)
               << total_forward_time / ((double) bench_runs * 1e6)
               << std::endl;
      out_file.close();
    }

    {
      bofs::path filep = benchpath;
      filep /= ("/process_memory_usage.csv");

      std::ofstream out_file;
      out_file.open(filep.string());
      assert(out_file.is_open());

      out_file << "Peak memory usage;"
          << net.layers()[0]->device_context()->peak_memory_usage()
          << std::endl;
      out_file.close();
    }
  }

  return 0;
}

}  // namespace caffe_neural
<commit_msg>More benchmark outputs.<commit_after>/*
 * benchmark.cpp
 *
 *  Created on: Jun 23, 2015
 *      Author: Fabian Tschopp
 */

#include "benchmark.hpp"
#include <vector>
#include <string>
#include <iostream>
#include <functional>
#include <chrono>
#include <cassert>
#include "../include/filesystem_utils.hpp"

namespace caffe_neural {

void FillNet(shared_ptr<Layer<float>> data_layer,
             shared_ptr<Layer<float>> label_layer, int num_output) {

  std::function<float()> rfu = GetRandomUniform<float>(-1.0, 1.0);
  std::function<float()> riu = GetRandomUniform(0, num_output);

  if (data_layer != NULL) {
    std::vector<cv::Mat> images;
    std::vector<int> labels;

    shared_ptr<caffe::MemoryDataLayer<float>> data_layer_ptr =
        boost::dynamic_pointer_cast<caffe::MemoryDataLayer<float>>(data_layer);

    // int bn = data_layer_ptr->batch_size();
    int bc = data_layer_ptr->channels();
    int bh = data_layer_ptr->height();
    int bw = data_layer_ptr->width();

    cv::Mat image(bh, bw, CV_32FC(bc));

#pragma omp parallel for
    for (int h = 0; h < bh; ++h) {
      for (int w = 0; w < bw; ++w) {
        for (int c = 0; c < bc; ++c) {
          *(image.ptr<float>(h, w) + c) = rfu();
        }
      }
    }

    images.push_back(image);
    labels.push_back(0);
    data_layer_ptr->AddMatVector(images, labels);

  }

  if (label_layer != NULL) {
    std::vector<cv::Mat> images;
    std::vector<int> labels;

    shared_ptr<caffe::MemoryDataLayer<float>> layer_ptr =
        boost::dynamic_pointer_cast<caffe::MemoryDataLayer<float>>(label_layer);

    // int bn = layer_ptr->batch_size();
    int bc = layer_ptr->channels();
    int bh = layer_ptr->height();
    int bw = layer_ptr->width();

    cv::Mat image(bh, bw, CV_32FC(bc));

#pragma omp parallel for
    for (int h = 0; h < bh; ++h) {
      for (int w = 0; w < bw; ++w) {
        for (int c = 0; c < bc; ++c) {
          *(image.ptr<float>(h, w) + c) = riu();
        }
      }
    }

    images.push_back(image);
    labels.push_back(0);
    layer_ptr->AddMatVector(images, labels);
  }
}

int Benchmark(caffe_neural::ToolParam &tool_param, CommonSettings &settings) {

  BenchmarkParam benchmark_param = tool_param.benchmark(settings.param_index);
  TrainParam train_param = tool_param.train(
      benchmark_param.has_train_index() ? benchmark_param.train_index() : 0);
  ProcessParam process_param = tool_param.process(
      benchmark_param.has_process_index() ?
          benchmark_param.process_index() : 0);

  int warmup_runs =
      benchmark_param.has_warmup_runs() ? benchmark_param.warmup_runs() : 0;
  int bench_runs =
      benchmark_param.has_bench_runs() ? benchmark_param.bench_runs() : 1;

  if (!benchmark_param.has_output()) {
    LOG(FATAL)<< "Missing output path for benchmarking.";

  }

  double tmp_time = 0;

  // Create output directories
  bofs::path benchpath(benchmark_param.output());
  bofs::create_directories(benchpath);

  std::string proto_solver = train_param.solver();
  std::string process_net = process_param.process_net();

  std::chrono::time_point<std::chrono::high_resolution_clock> t_start, t_end;

  // Benchmark block 1: Training Net
  if (benchmark_param.has_train_index()) {
    caffe::SolverParameter solver_param;
    caffe::ReadProtoFromTextFileOrDie(proto_solver, &solver_param);
    shared_ptr<caffe::Solver<float> > solver(
        caffe::GetSolver<float>(solver_param));
    boost::shared_ptr<caffe::Net<float>> net = solver->net();

    std::vector<double> layer_forward_times(net->layers().size());
    std::vector<double> layer_backward_times(net->layers().size());

    double total_forward_time = 0;
    double total_backward_time = 0;

    for (int run = 0; run < warmup_runs + bench_runs; ++run) {
      FillNet(net->layers()[1], net->layers()[0], train_param.input().labels());

      tmp_time = 0;

      // Benchmark 1: Layer wise measurements (forward)
      for (int l = 0; l < net->layers().size(); ++l) {
        t_start = std::chrono::high_resolution_clock::now();
        net->ForwardFromTo(l, l);
        Caffe::Synchronize(net->layers()[l]->device_context()->id());
        t_end = std::chrono::high_resolution_clock::now();
        tmp_time += (t_end - t_start).count();
        if (run >= warmup_runs) {
          layer_forward_times[l] += (t_end - t_start).count();
        }
      }
      LOG(INFO) << "Forward pass: " << std::setprecision(10)
          << (tmp_time)/((double)1e6) << " ms";

      tmp_time = 0;

      // Benchmark 2: Layer wise measurements (backward)
      for (int l = net->layers().size() - 1; l >= 0; --l) {
        t_start = std::chrono::high_resolution_clock::now();
        net->BackwardFromTo(l, l);
        Caffe::Synchronize(net->layers()[l]->device_context()->id());
        t_end = std::chrono::high_resolution_clock::now();
        tmp_time += (t_end - t_start).count();
        if (run >= warmup_runs) {
          layer_backward_times[l] += (t_end - t_start).count();
        }
      }
      LOG(INFO) << "Backward pass: " << std::setprecision(10)
          << (tmp_time)/((double)1e6) << " ms";

    }

    for (int run = 0; run < warmup_runs + bench_runs; ++run) {
      FillNet(net->layers()[1], net->layers()[0], train_param.input().labels());

      // Benchmark 3: Whole forward pass
      t_start = std::chrono::high_resolution_clock::now();
      net->ForwardPrefilled();
      Caffe::Synchronize(
          net->layers()[net->layers().size() - 1]->device_context()->id());
      t_end = std::chrono::high_resolution_clock::now();
      LOG(INFO) << "Forward pass: " << std::setprecision(10)
          << (double)((t_end - t_start).count())/((double)1e6) << " ms";
      if (run >= warmup_runs) {
        total_forward_time += (t_end - t_start).count();
      }

      // Benchmark 4: Whole backward pass
      t_start = std::chrono::high_resolution_clock::now();
      net->Backward();
      Caffe::Synchronize(net->layers()[0]->device_context()->id());
      t_end = std::chrono::high_resolution_clock::now();
      LOG(INFO) << "Backward pass: " << std::setprecision(10)
          << (double)((t_end - t_start).count())/((double)1e6) << " ms";
      if (run >= warmup_runs) {
        total_backward_time += (t_end - t_start).count();
      }
    }

    // Write outputs
    std::vector<std::string> layers = net->layer_names();

    {
      bofs::path filep = benchpath;
      filep /= ("/train_forward_layers_timings.csv");

      std::ofstream out_file;
      out_file.open(filep.string());
      assert(out_file.is_open());
      for (int l = 0; l < net->layers().size(); ++l) {
        out_file << l << ";" << layers[l] << ";"
                 << std::setprecision(10)
                 << layer_forward_times[l] / ((double) bench_runs * 1e6)
                 << std::endl;
      }
      out_file.close();
    }

    {
      bofs::path filep = benchpath;
      filep /= ("/train_backward_layers_timings.csv");

      std::ofstream out_file;
      out_file.open(filep.string());
      assert(out_file.is_open());
      for (int l = 0; l < net->layers().size(); ++l) {
        out_file << l << ";" << layers[l] << ";"
                 << std::setprecision(10)
                 << layer_backward_times[l] / ((double) bench_runs * 1e6)
                 << std::endl;
      }
      out_file.close();
    }

    {
      bofs::path filep = benchpath;
      filep /= ("/train_total_timings.csv");

      std::ofstream out_file;
      out_file.open(filep.string());
      assert(out_file.is_open());

      out_file << "Forward;" << std::setprecision(10)
               << total_forward_time / ((double) bench_runs * 1e6)
               << std::endl;

      out_file << "Backward;" << std::setprecision(10)
               << total_backward_time / ((double) bench_runs * 1e6)
               << std::endl;
      out_file.close();
    }

    {
      bofs::path filep = benchpath;
      filep /= ("/train_memory_usage.csv");

      std::ofstream out_file;
      out_file.open(filep.string());
      assert(out_file.is_open());

      out_file << "Peak memory usage;"
          << net->layers()[0]->device_context()->peak_memory_usage()
          << std::endl;
      out_file.close();
    }

  }

  // Benchmark block 2: Processing Net
  if (benchmark_param.has_process_index()) {
    Net<float> net(process_net, caffe::TEST);

    std::vector<double> layer_forward_times(net.layers().size());
    double total_forward_time = 0;

    // Benchmark 1: Layer wise measurements (forward)
    for (int run = 0; run < warmup_runs + bench_runs; ++run) {
      FillNet(net.layers()[0], NULL, train_param.input().labels());

      tmp_time = 0;
      // Benchmark 1: Layer wise measurements (forward)
      for (int l = 0; l < net.layers().size(); ++l) {
        t_start = std::chrono::high_resolution_clock::now();
        net.ForwardFromTo(l, l);
        Caffe::Synchronize(net.layers()[l]->device_context()->id());
        t_end = std::chrono::high_resolution_clock::now();
        tmp_time += (t_end - t_start).count();
        if (run >= warmup_runs) {
          layer_forward_times[l] += (t_end - t_start).count();
        }
      }
      LOG(INFO) << "Forward pass: " << std::setprecision(10)
          << (tmp_time)/((double)1e6) << " ms";
    }

    // Benchmark 2: Whole forward pass
    for (int run = 0; run < warmup_runs + bench_runs; ++run) {
      FillNet(net.layers()[0], NULL, train_param.input().labels());
      t_start = std::chrono::high_resolution_clock::now();
      net.ForwardPrefilled();
      Caffe::Synchronize(
          net.layers()[net.layers().size() - 1]->device_context()->id());
      t_end = std::chrono::high_resolution_clock::now();
      LOG(INFO) << "Forward pass: " << std::setprecision(10)
          << (double)((t_end - t_start).count())/((double)1e6) << " ms";
      if (run >= warmup_runs) {
        total_forward_time += (t_end - t_start).count();
      }
    }

    // Write outputs
    std::vector<std::string> layers = net.layer_names();

    {
      bofs::path filep = benchpath;
      filep /= ("/process_forward_layers_timings.csv");

      std::ofstream out_file;
      out_file.open(filep.string());
      assert(out_file.is_open());
      for (int l = 0; l < net.layers().size(); ++l) {
        out_file << l << ";" << layers[l] << ";"
                 << std::setprecision(10)
                 << layer_forward_times[l] / ((double) bench_runs * 1e6)
                 << std::endl;
      }
      out_file.close();
    }

    {
      bofs::path filep = benchpath;
      filep /= ("/process_total_timings.csv");

      std::ofstream out_file;
      out_file.open(filep.string());
      assert(out_file.is_open());

      out_file << "Forward;" << std::setprecision(10)
               << total_forward_time / ((double) bench_runs * 1e6)
               << std::endl;
      out_file.close();
    }

    {
      bofs::path filep = benchpath;
      filep /= ("/process_memory_usage.csv");

      std::ofstream out_file;
      out_file.open(filep.string());
      assert(out_file.is_open());

      out_file << "Peak memory usage;"
          << net.layers()[0]->device_context()->peak_memory_usage()
          << std::endl;
      out_file.close();
    }
  }

  return 0;
}

}  // namespace caffe_neural
<|endoftext|>


<commit_before>#pragma once
#ifndef BENCHMARK_HPP_778YQPEJ
#define BENCHMARK_HPP_778YQPEJ

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/current_function.hpp>
#include <vector>
#include <string>
#define BENCHMARK(list,exp) { benchmark::timer t(list,#exp,__FILE__,__LINE__,BOOST_CURRENT_FUNCTION); (exp); }

namespace benchmark
{
    struct event {
        const bool operator<(const event &other) const;
        friend std::ostream& operator<<(std::ostream &out, event &ev);

        std::string exp, file, function;
        boost::posix_time::time_duration time;
        unsigned int line, count;
    };

    class event_list
    {
    public:
        friend std::ostream& operator<<(std::ostream &out, event_list &el);
        event& max();
        boost::posix_time::time_duration average_time();
        void push_back(const event &ev);
        size_t size() const;
        const event front() const;

    private:
        typedef std::vector<event> actual_list_type;
        actual_list_type actual_list;
    };

    class timer
    {
    public:
        timer(event_list *list, const std::string exp, const std::string file, const unsigned int line, const std::string function);
        virtual ~timer();

    private:
        event_list *_list;
        const std::string _exp, _file;
        const unsigned int _line;
        const std::string _function;
        boost::posix_time::ptime *start, *end;
        std::ostringstream oss;
    };
}

#endif /* end of include guard: BENCHMARK_HPP_778YQPEJ */
<commit_msg>pass event_list by reference<commit_after>#pragma once
#ifndef BENCHMARK_HPP_778YQPEJ
#define BENCHMARK_HPP_778YQPEJ

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/current_function.hpp>
#include <vector>
#include <string>
#define BENCHMARK(list,exp) { benchmark::timer t(&list,#exp,__FILE__,__LINE__,BOOST_CURRENT_FUNCTION); (exp); }

namespace benchmark
{
    struct event {
        const bool operator<(const event &other) const;
        friend std::ostream& operator<<(std::ostream &out, event &ev);

        std::string exp, file, function;
        boost::posix_time::time_duration time;
        unsigned int line, count;
    };

    class event_list
    {
    public:
        friend std::ostream& operator<<(std::ostream &out, event_list &el);
        event& max();
        boost::posix_time::time_duration average_time();
        void push_back(const event &ev);
        size_t size() const;
        const event front() const;

    private:
        typedef std::vector<event> actual_list_type;
        actual_list_type actual_list;
    };

    class timer
    {
    public:
        timer(event_list *list, const std::string exp, const std::string file, const unsigned int line, const std::string function);
        virtual ~timer();

    private:
        event_list *_list;
        const std::string _exp, _file;
        const unsigned int _line;
        const std::string _function;
        boost::posix_time::ptime *start, *end;
        std::ostringstream oss;
    };
}

#endif /* end of include guard: BENCHMARK_HPP_778YQPEJ */
<|endoftext|>