<commit_before>/*
 * Copyright (c) 2011, Peter Thorson. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the WebSocket++ Project nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef WEBSOCKETPP_ENDPOINT_HPP
#define WEBSOCKETPP_ENDPOINT_HPP

#include "connection.hpp"
#include "sockets/plain.hpp" // should this be here?
#include "logger/logger.hpp"

#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>

#include <iostream>
#include <set>

namespace websocketpp {

/// endpoint_base provides core functionality that needs to be constructed
/// before endpoint policy classes are constructed.
class endpoint_base {
protected:
    /// Start the run method of the endpoint's io_service object.
    void run_internal() {
        m_io_service.run();
    }

    boost::asio::io_service m_io_service;
};

/// Describes a configurable WebSocket endpoint.
/**
 * The endpoint class template provides a configurable WebSocket endpoint
 * capable that manages WebSocket connection lifecycles. endpoint is a host
 * class to a series of enriched policy classes that together provide the public
 * interface for a specific type of WebSocket endpoint.
 *
 * @par Thread Safety
 * @e Distinct @e objects: Safe.@n
 * @e Shared @e objects: Will be safe when complete.
 */
template <
    template <class> class role,
    template <class> class socket = socket::plain,
    template <class> class logger = log::logger>
class endpoint
 : public endpoint_base,
   public role< endpoint<role,socket> >,
   public socket< endpoint<role,socket> >,
   boost::noncopyable
{
public:
    /// Type of the traits class that stores endpoint related types.
    typedef endpoint_traits< endpoint<role,socket,logger> > traits;

    /// The type of the endpoint itself.
    typedef typename traits::type type;
    /// The type of a shared pointer to the endpoint.
    typedef typename traits::ptr ptr;
    /// The type of the role policy.
    typedef typename traits::role_type role_type;
    /// The type of the socket policy.
    typedef typename traits::socket_type socket_type;
    /// The type of the access logger based on the logger policy.
    typedef typename traits::alogger_type alogger_type;
    /// The type of the error logger based on the logger policy.
    typedef typename traits::elogger_type elogger_type;
    /// The type of the connection that this endpoint creates.
    typedef typename traits::connection_type connection_type;
    /// A shared pointer to the type of connection that this endpoint creates.
    typedef typename traits::connection_ptr connection_ptr;
    /// Interface (ABC) that handlers for this type of endpoint must impliment
    /// role policy and socket policy both may add methods to this interface
    typedef typename traits::handler handler;
    /// A shared pointer to the base class that all handlers for this endpoint
    /// must derive from.
    typedef typename traits::handler_ptr handler_ptr;

    // Friend is used here to allow the CRTP base classes to access member
    // functions in the derived endpoint. This is done to limit the use of
    // public methods in endpoint and its CRTP bases to only those methods
    // intended for end-application use.
    friend class role< endpoint<role,socket> >;
    friend class socket< endpoint<role,socket> >;
    friend class connection<type,role< type >::template connection,socket< type >::template connection>;

    // Highly simplified and preferred C++11 version:
    // friend role_type;
    // friend socket_type;
    // friend connection_type;

    /// Construct an endpoint.
    /**
     * This constructor creates an endpoint and registers the default connection
     * handler.
     *
     * @param handler A shared_ptr to the handler to use as the default handler
     * when creating new connections.
     */
    explicit endpoint(handler_ptr handler)
     : role_type(endpoint_base::m_io_service),
       socket_type(endpoint_base::m_io_service),
       m_state(IDLE),
       m_handler(handler),
       m_pool(new message::pool<message::data>(1000)),
       m_pool_control(new message::pool<message::data>(SIZE_MAX))
    {
        m_pool->set_callback(boost::bind(&type::on_new_message,this));
    }

    /// Destroy and endpoint
    ~endpoint() {
        m_pool->set_callback(NULL);
        // TODO: destroy all connections associated with this endpoint?
    }

    // copy/assignment constructors require C++11
    // boost::noncopyable is being used in the meantime.
    // endpoint(endpoint const&) = delete;
    // endpoint& operator=(endpoint const&) = delete

    /// Returns a reference to the endpoint's access logger.
    /**
     * @return A reference to the endpoint's access logger. See @ref logger
     * for more details about WebSocket++ logging policy classes.
     *
     * @par Example
     * To print a message to the access log of endpoint e at access level DEVEL:
     * @code
     * e.alog().at(log::alevel::DEVEL) << "message" << log::endl;
     * @endcode
     */
    alogger_type& alog() {
        return m_alog;
    }

    /// Returns a reference to the endpoint's error logger.
    /**
     * @returns A reference to the endpoint's error logger. See @ref logger
     * for more details about WebSocket++ logging policy classes.
     *
     * @par Example
     * To print a message to the error log of endpoint e at access level DEVEL:
     * @code
     * e.elog().at(log::elevel::DEVEL) << "message" << log::endl;
     * @endcode
     */
    elogger_type& elog() {
        return m_elog;
    }

    /// Updates the default handler to be used for future connections
    /**
     * @param new_handler A shared pointer to the new default handler. Must not
     * be NULL.
     */
    void set_handler(handler_ptr new_handler) {
        if (!new_handler) {
            elog().at(log::elevel::FATAL)
                << "Tried to switch to a NULL handler." << log::endl;
            throw websocketpp::exception("TODO: handlers can't be null");
        }

        m_handler = new_handler;
    }

    /// Cleanly closes all websocket connections
    /**
     * Sends a close signal to every connection with the specified code and
     * reason. The default code is 1001/Going Away and the default reason is
     * blank.
     *
     * @param code The WebSocket close code to send to remote clients as the
     * reason that the connection is being closed.
     * @param reason The WebSocket close reason to send to remote clients as the
     * text reason that the connection is being closed. Must be valid UTF-8.
     */
    void close_all(close::status::value code = close::status::GOING_AWAY,
                   const std::string& reason = "")
    {
        alog().at(log::alevel::ENDPOINT)
        << "Endpoint received signal to close all connections cleanly with code "
        << code << " and reason " << reason << log::endl;

        // TODO: is there a more elegant way to do this? In some code paths
        // close can call terminate immediately which removes the connection
        // from m_connections, invalidating the iterator.
        while(!m_connections.empty()) {
            (*m_connections.begin())->close(code,reason);
        }
    }

    /// Stop the endpoint's ASIO loop
    /**
     * Signals the endpoint to call the io_service stop member function. If
     * clean is true the endpoint will be put into an intermediate state where
     * it signals all connections to close cleanly and only calls stop once that
     * process is complete. Otherwise stop is called immediately and all
     * io_service operations will be aborted.
     *
     * If clean is true stop will use code and reason for the close code and
     * close reason when it closes open connections. The default code is
     * 1001/Going Away and the default reason is blank.
     *
     * @param clean Whether or not to wait until all connections have been
     * cleanly closed to stop io_service operations.
     * @param code The WebSocket close code to send to remote clients as the
     * reason that the connection is being closed.
     * @param reason The WebSocket close reason to send to remote clients as the
     * text reason that the connection is being closed. Must be valid UTF-8.
     */
    void stop(bool clean = true,
              close::status::value code = close::status::GOING_AWAY,
              const std::string& reason = "")
    {
        if (clean) {
            alog().at(log::alevel::ENDPOINT)
            << "Endpoint is stopping cleanly" << log::endl;

            m_state = STOPPING;
            close_all(code,reason);
        } else {
            alog().at(log::alevel::ENDPOINT)
            << "Endpoint is stopping immediately" << log::endl;

            endpoint_base::m_io_service.stop();
            m_state = STOPPED;
        }
    }
protected:
    /// Creates and returns a new connection
    /**
     * This function creates a new connection of the type and passes it a
     * reference to this as well as a shared pointer to the default connection
     * handler. The newly created connection is added to the endpoint's
     * management list. The endpoint will retain this pointer until
     * remove_connection is called to remove it.
     *
     * If the endpoint is in a state where it is trying to stop or has already
     * stopped an empty shared pointer is returned.
     *
     * @return A shared pointer to the newly created connection or an empty
     * shared pointer if one could not be created.
     */
    connection_ptr create_connection() {
        if (m_state == STOPPING || m_state == STOPPED) {
            return connection_ptr();
        }

        connection_ptr new_connection(new connection_type(*this,get_handler()));
        m_connections.insert(new_connection);

        alog().at(log::alevel::DEVEL) << "Connection created: count is now: "
                                      << m_connections.size() << log::endl;

        return new_connection;
    }

    /// Removes a connection from the list managed by this endpoint.
    /**
     * This function erases a connection from the list managed by the endpoint.
     * After this function returns, endpoint all async events related to this
     * connection should be canceled and neither ASIO nor this endpoint should
     * have a pointer to this connection. Unless the end user retains a copy of
     * the shared pointer the connection will be freed and any state it
     * contained (close code status, etc) will be lost.
     *
     * @param con A shared pointer to a connection created by this endpoint.
     */
    void remove_connection(connection_ptr con) {
        m_connections.erase(con);

        alog().at(log::alevel::DEVEL) << "Connection removed: count is now: "
                                      << m_connections.size() << log::endl;

        if (m_state == STOPPING && m_connections.empty()) {
            // If we are in the process of stopping and have reached zero
            // connections stop the io_service.
            stop(false);
            alog().at(log::alevel::ENDPOINT)
                << "Endpoint has reached zero connections in STOPPING state. Stopping io_service now."
                << log::endl;
        }
    }

    /// Gets a shared pointer to this endpoint's default connection handler
    handler_ptr get_handler() {
        return m_handler;
    }

    /// Gets a shared pointer to a read/write data message.
    message::data::ptr get_data_message() {
		return m_pool->get();
	}

    /// Gets a shared pointer to a read/write control message.
    message::data::ptr get_control_message() {
		return m_pool_control->get();
	}

    /// Asks the endpoint to restart this connection's handle_read_frame loop
    /// when there are avaliable data messages.
    void wait(connection_ptr con) {
        m_read_waiting.push(con);
        alog().at(log::alevel::DEVEL) << "connection " << con << " is waiting. " << m_read_waiting.size() << log::endl;
    }

    /// Message pool callback indicating that there is a free data message
    /// avaliable. Causes one waiting connection to get restarted.
    void on_new_message() {
        if (!m_read_waiting.empty()) {
            connection_ptr next = m_read_waiting.front();

            alog().at(log::alevel::DEVEL) << "Waking connection " << next << ". " << m_read_waiting.size()-1 << log::endl;

            (*next).handle_read_frame(boost::system::error_code());
            m_read_waiting.pop();

        }
    }
private:
    enum state {
        IDLE = 0,
        RUNNING = 1,
        STOPPING = 2,
        STOPPED = 3
    };

    state                       m_state;
    handler_ptr                 m_handler;
    std::set<connection_ptr>    m_connections;
    alogger_type                m_alog;
    elogger_type                m_elog;

    // resource pools for read/write message buffers
    message::pool<message::data>::ptr   m_pool;
    message::pool<message::data>::ptr   m_pool_control;
    std::queue<connection_ptr>          m_read_waiting;
};

/// traits class that allows looking up relevant endpoint types by the fully
/// defined endpoint type.
template <
    template <class> class role,
    template <class> class socket,
    template <class> class logger>
struct endpoint_traits< endpoint<role, socket, logger> > {
    /// The type of the endpoint itself.
    typedef endpoint<role,socket,logger> type;
    typedef boost::shared_ptr<type> ptr;

    /// The type of the role policy.
    typedef role< type > role_type;
    /// The type of the socket policy.
    typedef socket< type > socket_type;

    /// The type of the access logger based on the logger policy.
    typedef logger<log::alevel::value> alogger_type;
    /// The type of the error logger based on the logger policy.
    typedef logger<log::elevel::value> elogger_type;

    /// The type of the connection that this endpoint creates.
    typedef connection<type,
                       role< type >::template connection,
                       socket< type >::template connection> connection_type;
    /// A shared pointer to the type of connection that this endpoint creates.
    typedef boost::shared_ptr<connection_type> connection_ptr;

    class handler;

    /// A shared pointer to the base class that all handlers for this endpoint
    /// must derive from.
    typedef boost::shared_ptr<handler> handler_ptr;

    /// Interface (ABC) that handlers for this type of endpoint may impliment.
    /// role policy and socket policy both may add methods to this interface
    class handler : public role_type::handler_interface,
                    public socket_type::handler_interface
    {
    public:
        // convenience typedefs for use in end application handlers.
        // TODO: figure out how to not duplicate the definition of connection_ptr
        typedef boost::shared_ptr<handler> ptr;
        typedef typename connection_type::ptr connection_ptr;
        typedef typename message::data::ptr message_ptr;

        virtual ~handler() {}

        /// on_load is the first callback called for a handler after a new
        /// connection has been transferred to it mid flight.
        /**
         * @param connection A shared pointer to the connection that was transferred
         * @param old_handler A shared pointer to the previous handler
         */
        virtual void on_load(connection_ptr connection, handler_ptr old_handler) {}
        /// on_unload is the last callback called for a handler before control
        /// of a connection is handed over to a new handler mid flight.
        /**
         * @param connection A shared pointer to the connection being transferred
         * @param old_handler A shared pointer to the new handler
         */
        virtual void on_unload(connection_ptr connection, handler_ptr new_handler) {}
    };

};

} // namespace websocketpp

#endif // WEBSOCKETPP_ENDPOINT_HPP
<commit_msg>initial fixes for custom logging, references #56<commit_after>/*
 * Copyright (c) 2011, Peter Thorson. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the WebSocket++ Project nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef WEBSOCKETPP_ENDPOINT_HPP
#define WEBSOCKETPP_ENDPOINT_HPP

#include "connection.hpp"
#include "sockets/plain.hpp" // should this be here?
#include "logger/logger.hpp"

#include <boost/asio.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/utility.hpp>

#include <iostream>
#include <set>

namespace websocketpp {

/// endpoint_base provides core functionality that needs to be constructed
/// before endpoint policy classes are constructed.
class endpoint_base {
protected:
    /// Start the run method of the endpoint's io_service object.
    void run_internal() {
        m_io_service.run();
    }

    boost::asio::io_service m_io_service;
};

/// Describes a configurable WebSocket endpoint.
/**
 * The endpoint class template provides a configurable WebSocket endpoint
 * capable that manages WebSocket connection lifecycles. endpoint is a host
 * class to a series of enriched policy classes that together provide the public
 * interface for a specific type of WebSocket endpoint.
 *
 * @par Thread Safety
 * @e Distinct @e objects: Safe.@n
 * @e Shared @e objects: Will be safe when complete.
 */
template <
    template <class> class role,
    template <class> class socket = socket::plain,
    template <class> class logger = log::logger>
class endpoint
 : public endpoint_base,
   public role< endpoint<role,socket,logger> >,
   public socket< endpoint<role,socket,logger> >,
   boost::noncopyable
{
public:
    /// Type of the traits class that stores endpoint related types.
    typedef endpoint_traits< endpoint<role,socket,logger> > traits;

    /// The type of the endpoint itself.
    typedef typename traits::type type;
    /// The type of a shared pointer to the endpoint.
    typedef typename traits::ptr ptr;
    /// The type of the role policy.
    typedef typename traits::role_type role_type;
    /// The type of the socket policy.
    typedef typename traits::socket_type socket_type;
    /// The type of the access logger based on the logger policy.
    typedef typename traits::alogger_type alogger_type;
    /// The type of the error logger based on the logger policy.
    typedef typename traits::elogger_type elogger_type;
    /// The type of the connection that this endpoint creates.
    typedef typename traits::connection_type connection_type;
    /// A shared pointer to the type of connection that this endpoint creates.
    typedef typename traits::connection_ptr connection_ptr;
    /// Interface (ABC) that handlers for this type of endpoint must impliment
    /// role policy and socket policy both may add methods to this interface
    typedef typename traits::handler handler;
    /// A shared pointer to the base class that all handlers for this endpoint
    /// must derive from.
    typedef typename traits::handler_ptr handler_ptr;

    // Friend is used here to allow the CRTP base classes to access member
    // functions in the derived endpoint. This is done to limit the use of
    // public methods in endpoint and its CRTP bases to only those methods
    // intended for end-application use.
    friend class role< endpoint<role,socket> >;
    friend class socket< endpoint<role,socket> >;
    friend class connection<type,role< type >::template connection,socket< type >::template connection>;

    // Highly simplified and preferred C++11 version:
    // friend role_type;
    // friend socket_type;
    // friend connection_type;

    /// Construct an endpoint.
    /**
     * This constructor creates an endpoint and registers the default connection
     * handler.
     *
     * @param handler A shared_ptr to the handler to use as the default handler
     * when creating new connections.
     */
    explicit endpoint(handler_ptr handler)
     : role_type(endpoint_base::m_io_service),
       socket_type(endpoint_base::m_io_service),
       m_state(IDLE),
       m_handler(handler),
       m_pool(new message::pool<message::data>(1000)),
       m_pool_control(new message::pool<message::data>(SIZE_MAX))
    {
        m_pool->set_callback(boost::bind(&type::on_new_message,this));
    }

    /// Destroy and endpoint
    ~endpoint() {
        m_pool->set_callback(NULL);
        // TODO: destroy all connections associated with this endpoint?
    }

    // copy/assignment constructors require C++11
    // boost::noncopyable is being used in the meantime.
    // endpoint(endpoint const&) = delete;
    // endpoint& operator=(endpoint const&) = delete

    /// Returns a reference to the endpoint's access logger.
    /**
     * @return A reference to the endpoint's access logger. See @ref logger
     * for more details about WebSocket++ logging policy classes.
     *
     * @par Example
     * To print a message to the access log of endpoint e at access level DEVEL:
     * @code
     * e.alog().at(log::alevel::DEVEL) << "message" << log::endl;
     * @endcode
     */
    alogger_type& alog() {
        return m_alog;
    }

    /// Returns a reference to the endpoint's error logger.
    /**
     * @returns A reference to the endpoint's error logger. See @ref logger
     * for more details about WebSocket++ logging policy classes.
     *
     * @par Example
     * To print a message to the error log of endpoint e at access level DEVEL:
     * @code
     * e.elog().at(log::elevel::DEVEL) << "message" << log::endl;
     * @endcode
     */
    elogger_type& elog() {
        return m_elog;
    }

    /// Updates the default handler to be used for future connections
    /**
     * @param new_handler A shared pointer to the new default handler. Must not
     * be NULL.
     */
    void set_handler(handler_ptr new_handler) {
        if (!new_handler) {
            elog().at(log::elevel::FATAL)
                << "Tried to switch to a NULL handler." << log::endl;
            throw websocketpp::exception("TODO: handlers can't be null");
        }

        m_handler = new_handler;
    }

    /// Cleanly closes all websocket connections
    /**
     * Sends a close signal to every connection with the specified code and
     * reason. The default code is 1001/Going Away and the default reason is
     * blank.
     *
     * @param code The WebSocket close code to send to remote clients as the
     * reason that the connection is being closed.
     * @param reason The WebSocket close reason to send to remote clients as the
     * text reason that the connection is being closed. Must be valid UTF-8.
     */
    void close_all(close::status::value code = close::status::GOING_AWAY,
                   const std::string& reason = "")
    {
        alog().at(log::alevel::ENDPOINT)
        << "Endpoint received signal to close all connections cleanly with code "
        << code << " and reason " << reason << log::endl;

        // TODO: is there a more elegant way to do this? In some code paths
        // close can call terminate immediately which removes the connection
        // from m_connections, invalidating the iterator.
        while(!m_connections.empty()) {
            (*m_connections.begin())->close(code,reason);
        }
    }

    /// Stop the endpoint's ASIO loop
    /**
     * Signals the endpoint to call the io_service stop member function. If
     * clean is true the endpoint will be put into an intermediate state where
     * it signals all connections to close cleanly and only calls stop once that
     * process is complete. Otherwise stop is called immediately and all
     * io_service operations will be aborted.
     *
     * If clean is true stop will use code and reason for the close code and
     * close reason when it closes open connections. The default code is
     * 1001/Going Away and the default reason is blank.
     *
     * @param clean Whether or not to wait until all connections have been
     * cleanly closed to stop io_service operations.
     * @param code The WebSocket close code to send to remote clients as the
     * reason that the connection is being closed.
     * @param reason The WebSocket close reason to send to remote clients as the
     * text reason that the connection is being closed. Must be valid UTF-8.
     */
    void stop(bool clean = true,
              close::status::value code = close::status::GOING_AWAY,
              const std::string& reason = "")
    {
        if (clean) {
            alog().at(log::alevel::ENDPOINT)
            << "Endpoint is stopping cleanly" << log::endl;

            m_state = STOPPING;
            close_all(code,reason);
        } else {
            alog().at(log::alevel::ENDPOINT)
            << "Endpoint is stopping immediately" << log::endl;

            endpoint_base::m_io_service.stop();
            m_state = STOPPED;
        }
    }
protected:
    /// Creates and returns a new connection
    /**
     * This function creates a new connection of the type and passes it a
     * reference to this as well as a shared pointer to the default connection
     * handler. The newly created connection is added to the endpoint's
     * management list. The endpoint will retain this pointer until
     * remove_connection is called to remove it.
     *
     * If the endpoint is in a state where it is trying to stop or has already
     * stopped an empty shared pointer is returned.
     *
     * @return A shared pointer to the newly created connection or an empty
     * shared pointer if one could not be created.
     */
    connection_ptr create_connection() {
        if (m_state == STOPPING || m_state == STOPPED) {
            return connection_ptr();
        }

        connection_ptr new_connection(new connection_type(*this,get_handler()));
        m_connections.insert(new_connection);

        alog().at(log::alevel::DEVEL) << "Connection created: count is now: "
                                      << m_connections.size() << log::endl;

        return new_connection;
    }

    /// Removes a connection from the list managed by this endpoint.
    /**
     * This function erases a connection from the list managed by the endpoint.
     * After this function returns, endpoint all async events related to this
     * connection should be canceled and neither ASIO nor this endpoint should
     * have a pointer to this connection. Unless the end user retains a copy of
     * the shared pointer the connection will be freed and any state it
     * contained (close code status, etc) will be lost.
     *
     * @param con A shared pointer to a connection created by this endpoint.
     */
    void remove_connection(connection_ptr con) {
        m_connections.erase(con);

        alog().at(log::alevel::DEVEL) << "Connection removed: count is now: "
                                      << m_connections.size() << log::endl;

        if (m_state == STOPPING && m_connections.empty()) {
            // If we are in the process of stopping and have reached zero
            // connections stop the io_service.
            stop(false);
            alog().at(log::alevel::ENDPOINT)
                << "Endpoint has reached zero connections in STOPPING state. Stopping io_service now."
                << log::endl;
        }
    }

    /// Gets a shared pointer to this endpoint's default connection handler
    handler_ptr get_handler() {
        return m_handler;
    }

    /// Gets a shared pointer to a read/write data message.
    message::data::ptr get_data_message() {
		return m_pool->get();
	}

    /// Gets a shared pointer to a read/write control message.
    message::data::ptr get_control_message() {
		return m_pool_control->get();
	}

    /// Asks the endpoint to restart this connection's handle_read_frame loop
    /// when there are avaliable data messages.
    void wait(connection_ptr con) {
        m_read_waiting.push(con);
        alog().at(log::alevel::DEVEL) << "connection " << con << " is waiting. " << m_read_waiting.size() << log::endl;
    }

    /// Message pool callback indicating that there is a free data message
    /// avaliable. Causes one waiting connection to get restarted.
    void on_new_message() {
        if (!m_read_waiting.empty()) {
            connection_ptr next = m_read_waiting.front();

            alog().at(log::alevel::DEVEL) << "Waking connection " << next << ". " << m_read_waiting.size()-1 << log::endl;

            (*next).handle_read_frame(boost::system::error_code());
            m_read_waiting.pop();

        }
    }
private:
    enum state {
        IDLE = 0,
        RUNNING = 1,
        STOPPING = 2,
        STOPPED = 3
    };

    state                       m_state;
    handler_ptr                 m_handler;
    std::set<connection_ptr>    m_connections;
    alogger_type                m_alog;
    elogger_type                m_elog;

    // resource pools for read/write message buffers
    message::pool<message::data>::ptr   m_pool;
    message::pool<message::data>::ptr   m_pool_control;
    std::queue<connection_ptr>          m_read_waiting;
};

/// traits class that allows looking up relevant endpoint types by the fully
/// defined endpoint type.
template <
    template <class> class role,
    template <class> class socket,
    template <class> class logger>
struct endpoint_traits< endpoint<role, socket, logger> > {
    /// The type of the endpoint itself.
    typedef endpoint<role,socket,logger> type;
    typedef boost::shared_ptr<type> ptr;

    /// The type of the role policy.
    typedef role< type > role_type;
    /// The type of the socket policy.
    typedef socket< type > socket_type;

    /// The type of the access logger based on the logger policy.
    typedef logger<log::alevel::value> alogger_type;
    /// The type of the error logger based on the logger policy.
    typedef logger<log::elevel::value> elogger_type;

    /// The type of the connection that this endpoint creates.
    typedef connection<type,
                       role< type >::template connection,
                       socket< type >::template connection> connection_type;
    /// A shared pointer to the type of connection that this endpoint creates.
    typedef boost::shared_ptr<connection_type> connection_ptr;

    class handler;

    /// A shared pointer to the base class that all handlers for this endpoint
    /// must derive from.
    typedef boost::shared_ptr<handler> handler_ptr;

    /// Interface (ABC) that handlers for this type of endpoint may impliment.
    /// role policy and socket policy both may add methods to this interface
    class handler : public role_type::handler_interface,
                    public socket_type::handler_interface
    {
    public:
        // convenience typedefs for use in end application handlers.
        // TODO: figure out how to not duplicate the definition of connection_ptr
        typedef boost::shared_ptr<handler> ptr;
        typedef typename connection_type::ptr connection_ptr;
        typedef typename message::data::ptr message_ptr;

        virtual ~handler() {}

        /// on_load is the first callback called for a handler after a new
        /// connection has been transferred to it mid flight.
        /**
         * @param connection A shared pointer to the connection that was transferred
         * @param old_handler A shared pointer to the previous handler
         */
        virtual void on_load(connection_ptr connection, handler_ptr old_handler) {}
        /// on_unload is the last callback called for a handler before control
        /// of a connection is handed over to a new handler mid flight.
        /**
         * @param connection A shared pointer to the connection being transferred
         * @param old_handler A shared pointer to the new handler
         */
        virtual void on_unload(connection_ptr connection, handler_ptr new_handler) {}
    };

};

} // namespace websocketpp

#endif // WEBSOCKETPP_ENDPOINT_HPP
<|endoftext|>


<commit_before>/*
 *            Copyright 2009-2020 The VOTCA Development Team
 *                       (http://www.votca.org)
 *
 *      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 "eqm.h"
#include "votca/xtp/segmentmapper.h"
#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <boost/math/constants/constants.hpp>
#include <votca/xtp/esp2multipole.h>

using boost::format;
using namespace boost::filesystem;

namespace votca {
namespace xtp {

void EQM::Initialize(tools::Property& user_options) {

  LoadDefaultsAndUpdateWithUserOptions("xtp", user_options);
  ParseCommonOptions();
  QMPackageFactory::RegisterAll();

  // job tasks
  std::string _tasks_string = _options.get(".tasks").as<std::string>();

  if (_tasks_string.find("input") != std::string::npos) {
    _do_dft_input = true;
  }
  if (_tasks_string.find("dft") != std::string::npos) {
    _do_dft_run = true;
  }
  if (_tasks_string.find("parse") != std::string::npos) {
    _do_dft_parse = true;
  }
  if (_tasks_string.find("gwbse") != std::string::npos) {
    _do_gwbse = true;
  }
  if (_tasks_string.find("esp") != std::string::npos) {
    _do_esp = true;
  }

  _gwbse_options = _options.get(".gwbse_options");
  _package_options = _options.get(".dftpackage");
  _esp_options = _options.get(".esp_options");
}

void EQM::WriteJobFile(const Topology& top) {

  std::cout
            << "\n... ... Writing job file: " << _jobfile << std::flush;
  std::ofstream ofs;
  ofs.open(_jobfile, std::ofstream::out);
  if (!ofs.is_open()) {
    throw std::runtime_error("\nERROR: bad file handle: " + _jobfile);
  }
  ofs << "<jobs>" << std::endl;
  Index jobCount = 0;

  const std::vector<Segment>& segments = top.Segments();
  for (const Segment& segment : segments) {
    Index id = segment.getId();
    std::string tag = "";
    tools::Property Input;
    tools::Property& pInput = Input.add("input", "");
    tools::Property& pSegment =
        pInput.add("segment", (format("%1$s") % segment.getId()).str());
    pSegment.setAttribute<std::string>("type", segment.getType());
    pSegment.setAttribute<Index>("id", segment.getId());
    Job job(id, tag, Input, Job::AVAILABLE);
    job.ToStream(ofs);
    jobCount++;
  }

  ofs << "</jobs>" << std::endl;
  ofs.close();

  std::cout << jobCount << " jobs" << std::flush;
}

void EQM::SetJobToFailed(Job::JobResult& jres, Logger& pLog,
                         const std::string& errormessage) {
  XTP_LOG(Log::error, pLog) << errormessage << std::flush;
  std::cout << pLog;
  jres.setError(errormessage);
  jres.setStatus(Job::FAILED);
}

void EQM::WriteLoggerToFile(const std::string& logfile, Logger& logger) {
  std::ofstream ofs;
  ofs.open(logfile, std::ofstream::out);
  if (!ofs.is_open()) {
    throw std::runtime_error("Bad file handle: " + logfile);
  }
  ofs << logger << std::endl;
  ofs.close();
}

Job::JobResult EQM::EvalJob(const Topology& top, Job& job, QMThread& opThread) {
  Orbitals orbitals;
  Job::JobResult jres = Job::JobResult();
  tools::Property _job_input = job.getInput();
  std::vector<tools::Property*> lSegments = _job_input.Select("segment");
  Index segId = lSegments.front()->getAttribute<Index>("id");
  std::string segType = lSegments.front()->getAttribute<std::string>("type");
  std::string qmgeo_state = "n";
  if (lSegments.front()->exists("qm_geometry")) {
    qmgeo_state = lSegments.front()->getAttribute<std::string>("qm_geometry");
  }

  QMState state(qmgeo_state);
  const Segment& seg = top.getSegment(segId);

  Logger& pLog = opThread.getLogger();
  QMMapper mapper(pLog);
  mapper.LoadMappingFile(_mapfile);
  orbitals.QMAtoms() = mapper.map(seg, state);
  XTP_LOG(Log::error, pLog)
      << TimeStamp() << " Evaluating site " << seg.getId() << std::flush;

  // directories and files
  boost::filesystem::path arg_path;
  std::string eqm_work_dir = "OR_FILES";
  std::string frame_dir =
      "frame_" + boost::lexical_cast<std::string>(top.getStep());
  std::string orb_file =
      (format("%1%_%2%%3%") % "molecule" % segId % ".orb").str();
  std::string mol_dir = (format("%1%%2%%3%") % "molecule" % "_" % segId).str();
  std::string package_append = "workdir_" + Identify();
  std::string work_dir =
      (arg_path / eqm_work_dir / package_append / frame_dir / mol_dir)
          .generic_string();

  tools::Property job_summary;
  tools::Property& output_summary = job_summary.add("output", "");
  tools::Property& segment_summary = output_summary.add("segment", "");
  std::string segName = seg.getType();
  segId = seg.getId();
  segment_summary.setAttribute("id", segId);
  segment_summary.setAttribute("type", segName);
  if (_do_dft_input || _do_dft_run || _do_dft_parse) {
    XTP_LOG(Log::error, pLog) << "Running DFT" << std::flush;
    Logger dft_logger(votca::Log::current_level);
    dft_logger.setMultithreading(false);
    dft_logger.setPreface(Log::info, (format("\nDFT INF ...")).str());
    dft_logger.setPreface(Log::error, (format("\nDFT ERR ...")).str());
    dft_logger.setPreface(Log::warning, (format("\nDFT WAR ...")).str());
    dft_logger.setPreface(Log::debug, (format("\nDFT DBG ...")).str());
    std::string dft_key = "package";
    std::string package =
        _package_options.get(dft_key + ".name").as<std::string>();
    std::unique_ptr<QMPackage> qmpackage =
        std::unique_ptr<QMPackage>(QMPackages().Create(package));
    qmpackage->setLog(&dft_logger);
    qmpackage->setRunDir(work_dir);
    qmpackage->Initialize(_package_options);

    // create input for DFT
    if (_do_dft_input) {
      boost::filesystem::create_directories(work_dir);
      qmpackage->WriteInputFile(orbitals);
    }

    if (_do_dft_run) {
      bool run_dft_status = qmpackage->Run();
      if (!run_dft_status) {
        std::string output = "DFT run failed";
        SetJobToFailed(jres, pLog, output);
        return jres;
      }
    }

    // parse the log/orbitals files
    if (_do_dft_parse) {
      bool parse_log_status = qmpackage->ParseLogFile(orbitals);
      if (!parse_log_status) {
        std::string output = "log incomplete; ";
        SetJobToFailed(jres, pLog, output);
        return jres;
      }
      bool parse_orbitals_status = qmpackage->ParseMOsFile(orbitals);
      if (!parse_orbitals_status) {
        std::string output = "orbfile failed; ";
        SetJobToFailed(jres, pLog, output);
        return jres;
      }
    }  // end of the parse orbitals/log
    qmpackage->CleanUp();
    WriteLoggerToFile(work_dir + "/dft.log", dft_logger);
  }

  if (!_do_dft_parse) {
    // load the DFT data from serialized orbitals object
    std::string ORB_FILE =
        eqm_work_dir + "/molecules/" + frame_dir + "/" + orb_file;
    XTP_LOG(Log::error, pLog)
        << TimeStamp() << " Loading DFT data from " << ORB_FILE << std::flush;
    orbitals.ReadFromCpt(ORB_FILE);
  }

  if (_do_gwbse) {
    XTP_LOG(Log::error, pLog) << "Running GWBSE" << std::flush;
    try {
      GWBSE gwbse = GWBSE(orbitals);
      Logger gwbse_logger(votca::Log::current_level);
      gwbse_logger.setMultithreading(false);
      gwbse_logger.setPreface(Log::info, (format("\nGWBSE INF ...")).str());
      gwbse_logger.setPreface(Log::error, (format("\nGWBSE ERR ...")).str());
      gwbse_logger.setPreface(Log::warning, (format("\nGWBSE WAR ...")).str());
      gwbse_logger.setPreface(Log::debug, (format("\nGWBSE DBG ...")).str());
      gwbse.setLogger(&gwbse_logger);
      gwbse.Initialize(_gwbse_options);
      gwbse.Evaluate();
      gwbse.addoutput(segment_summary);
      WriteLoggerToFile(work_dir + "/gwbse.log", gwbse_logger);
    } catch (std::runtime_error& error) {
      std::string errormessage(error.what());
      SetJobToFailed(jres, pLog, "GWBSE:" + errormessage);
      return jres;
    }
  }

  if (_do_esp) {
    XTP_LOG(Log::error, pLog) << "Running ESPFIT" << std::flush;
    try {
      Esp2multipole esp2multipole = Esp2multipole(pLog);
      esp2multipole.Initialize(_esp_options);
      std::string ESPDIR =
          "MP_FILES/" + frame_dir + "/" + esp2multipole.GetStateString();
      StaticSegment seg2 = esp2multipole.Extractingcharges(orbitals);
      std::string mps_file = (format("%1%_%2%_%3%.mps") % segType % segId %
                              esp2multipole.GetStateString())
                                 .str();
      boost::filesystem::create_directories(ESPDIR);
      seg2.WriteMPS(ESPDIR + "/" + mps_file,
                    "Generated by eqm:" + esp2multipole.GetStateString());
      XTP_LOG(Log::error, pLog)
          << "Written charges to " << (ESPDIR + "/" + mps_file) << std::flush;
      segment_summary.add("partialcharges", (ESPDIR + "/" + mps_file));
    } catch (std::runtime_error& error) {
      std::string errormessage(error.what());
      SetJobToFailed(jres, pLog, "ESPFIT:" + errormessage);
      return jres;
    }
  }
  XTP_LOG(Log::error, pLog) << TimeStamp() << " Finished evaluating site "
                            << seg.getId() << std::flush;

  if (_do_dft_parse || _do_gwbse) {
    XTP_LOG(Log::error, pLog) << "Saving data to " << orb_file << std::flush;
    std::string DIR = eqm_work_dir + "/molecules/" + frame_dir;
    boost::filesystem::create_directories(DIR);
    std::string ORBFILE = DIR + "/" + orb_file;
    orbitals.WriteToCpt(ORBFILE);
  }

  // output of the JOB
  jres.setOutput(job_summary);
  jres.setStatus(Job::COMPLETE);

  return jres;
}
}  // namespace xtp
}  // namespace votca
<commit_msg>make format<commit_after>/*
 *            Copyright 2009-2020 The VOTCA Development Team
 *                       (http://www.votca.org)
 *
 *      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 "eqm.h"
#include "votca/xtp/segmentmapper.h"
#include <boost/filesystem.hpp>
#include <boost/format.hpp>
#include <boost/math/constants/constants.hpp>
#include <votca/xtp/esp2multipole.h>

using boost::format;
using namespace boost::filesystem;

namespace votca {
namespace xtp {

void EQM::Initialize(tools::Property& user_options) {

  LoadDefaultsAndUpdateWithUserOptions("xtp", user_options);
  ParseCommonOptions();
  QMPackageFactory::RegisterAll();

  // job tasks
  std::string _tasks_string = _options.get(".tasks").as<std::string>();

  if (_tasks_string.find("input") != std::string::npos) {
    _do_dft_input = true;
  }
  if (_tasks_string.find("dft") != std::string::npos) {
    _do_dft_run = true;
  }
  if (_tasks_string.find("parse") != std::string::npos) {
    _do_dft_parse = true;
  }
  if (_tasks_string.find("gwbse") != std::string::npos) {
    _do_gwbse = true;
  }
  if (_tasks_string.find("esp") != std::string::npos) {
    _do_esp = true;
  }

  _gwbse_options = _options.get(".gwbse_options");
  _package_options = _options.get(".dftpackage");
  _esp_options = _options.get(".esp_options");
}

void EQM::WriteJobFile(const Topology& top) {

  std::cout << "\n... ... Writing job file: " << _jobfile << std::flush;
  std::ofstream ofs;
  ofs.open(_jobfile, std::ofstream::out);
  if (!ofs.is_open()) {
    throw std::runtime_error("\nERROR: bad file handle: " + _jobfile);
  }
  ofs << "<jobs>" << std::endl;
  Index jobCount = 0;

  const std::vector<Segment>& segments = top.Segments();
  for (const Segment& segment : segments) {
    Index id = segment.getId();
    std::string tag = "";
    tools::Property Input;
    tools::Property& pInput = Input.add("input", "");
    tools::Property& pSegment =
        pInput.add("segment", (format("%1$s") % segment.getId()).str());
    pSegment.setAttribute<std::string>("type", segment.getType());
    pSegment.setAttribute<Index>("id", segment.getId());
    Job job(id, tag, Input, Job::AVAILABLE);
    job.ToStream(ofs);
    jobCount++;
  }

  ofs << "</jobs>" << std::endl;
  ofs.close();

  std::cout << jobCount << " jobs" << std::flush;
}

void EQM::SetJobToFailed(Job::JobResult& jres, Logger& pLog,
                         const std::string& errormessage) {
  XTP_LOG(Log::error, pLog) << errormessage << std::flush;
  std::cout << pLog;
  jres.setError(errormessage);
  jres.setStatus(Job::FAILED);
}

void EQM::WriteLoggerToFile(const std::string& logfile, Logger& logger) {
  std::ofstream ofs;
  ofs.open(logfile, std::ofstream::out);
  if (!ofs.is_open()) {
    throw std::runtime_error("Bad file handle: " + logfile);
  }
  ofs << logger << std::endl;
  ofs.close();
}

Job::JobResult EQM::EvalJob(const Topology& top, Job& job, QMThread& opThread) {
  Orbitals orbitals;
  Job::JobResult jres = Job::JobResult();
  tools::Property _job_input = job.getInput();
  std::vector<tools::Property*> lSegments = _job_input.Select("segment");
  Index segId = lSegments.front()->getAttribute<Index>("id");
  std::string segType = lSegments.front()->getAttribute<std::string>("type");
  std::string qmgeo_state = "n";
  if (lSegments.front()->exists("qm_geometry")) {
    qmgeo_state = lSegments.front()->getAttribute<std::string>("qm_geometry");
  }

  QMState state(qmgeo_state);
  const Segment& seg = top.getSegment(segId);

  Logger& pLog = opThread.getLogger();
  QMMapper mapper(pLog);
  mapper.LoadMappingFile(_mapfile);
  orbitals.QMAtoms() = mapper.map(seg, state);
  XTP_LOG(Log::error, pLog)
      << TimeStamp() << " Evaluating site " << seg.getId() << std::flush;

  // directories and files
  boost::filesystem::path arg_path;
  std::string eqm_work_dir = "OR_FILES";
  std::string frame_dir =
      "frame_" + boost::lexical_cast<std::string>(top.getStep());
  std::string orb_file =
      (format("%1%_%2%%3%") % "molecule" % segId % ".orb").str();
  std::string mol_dir = (format("%1%%2%%3%") % "molecule" % "_" % segId).str();
  std::string package_append = "workdir_" + Identify();
  std::string work_dir =
      (arg_path / eqm_work_dir / package_append / frame_dir / mol_dir)
          .generic_string();

  tools::Property job_summary;
  tools::Property& output_summary = job_summary.add("output", "");
  tools::Property& segment_summary = output_summary.add("segment", "");
  std::string segName = seg.getType();
  segId = seg.getId();
  segment_summary.setAttribute("id", segId);
  segment_summary.setAttribute("type", segName);
  if (_do_dft_input || _do_dft_run || _do_dft_parse) {
    XTP_LOG(Log::error, pLog) << "Running DFT" << std::flush;
    Logger dft_logger(votca::Log::current_level);
    dft_logger.setMultithreading(false);
    dft_logger.setPreface(Log::info, (format("\nDFT INF ...")).str());
    dft_logger.setPreface(Log::error, (format("\nDFT ERR ...")).str());
    dft_logger.setPreface(Log::warning, (format("\nDFT WAR ...")).str());
    dft_logger.setPreface(Log::debug, (format("\nDFT DBG ...")).str());
    std::string dft_key = "package";
    std::string package =
        _package_options.get(dft_key + ".name").as<std::string>();
    std::unique_ptr<QMPackage> qmpackage =
        std::unique_ptr<QMPackage>(QMPackages().Create(package));
    qmpackage->setLog(&dft_logger);
    qmpackage->setRunDir(work_dir);
    qmpackage->Initialize(_package_options);

    // create input for DFT
    if (_do_dft_input) {
      boost::filesystem::create_directories(work_dir);
      qmpackage->WriteInputFile(orbitals);
    }

    if (_do_dft_run) {
      bool run_dft_status = qmpackage->Run();
      if (!run_dft_status) {
        std::string output = "DFT run failed";
        SetJobToFailed(jres, pLog, output);
        return jres;
      }
    }

    // parse the log/orbitals files
    if (_do_dft_parse) {
      bool parse_log_status = qmpackage->ParseLogFile(orbitals);
      if (!parse_log_status) {
        std::string output = "log incomplete; ";
        SetJobToFailed(jres, pLog, output);
        return jres;
      }
      bool parse_orbitals_status = qmpackage->ParseMOsFile(orbitals);
      if (!parse_orbitals_status) {
        std::string output = "orbfile failed; ";
        SetJobToFailed(jres, pLog, output);
        return jres;
      }
    }  // end of the parse orbitals/log
    qmpackage->CleanUp();
    WriteLoggerToFile(work_dir + "/dft.log", dft_logger);
  }

  if (!_do_dft_parse) {
    // load the DFT data from serialized orbitals object
    std::string ORB_FILE =
        eqm_work_dir + "/molecules/" + frame_dir + "/" + orb_file;
    XTP_LOG(Log::error, pLog)
        << TimeStamp() << " Loading DFT data from " << ORB_FILE << std::flush;
    orbitals.ReadFromCpt(ORB_FILE);
  }

  if (_do_gwbse) {
    XTP_LOG(Log::error, pLog) << "Running GWBSE" << std::flush;
    try {
      GWBSE gwbse = GWBSE(orbitals);
      Logger gwbse_logger(votca::Log::current_level);
      gwbse_logger.setMultithreading(false);
      gwbse_logger.setPreface(Log::info, (format("\nGWBSE INF ...")).str());
      gwbse_logger.setPreface(Log::error, (format("\nGWBSE ERR ...")).str());
      gwbse_logger.setPreface(Log::warning, (format("\nGWBSE WAR ...")).str());
      gwbse_logger.setPreface(Log::debug, (format("\nGWBSE DBG ...")).str());
      gwbse.setLogger(&gwbse_logger);
      gwbse.Initialize(_gwbse_options);
      gwbse.Evaluate();
      gwbse.addoutput(segment_summary);
      WriteLoggerToFile(work_dir + "/gwbse.log", gwbse_logger);
    } catch (std::runtime_error& error) {
      std::string errormessage(error.what());
      SetJobToFailed(jres, pLog, "GWBSE:" + errormessage);
      return jres;
    }
  }

  if (_do_esp) {
    XTP_LOG(Log::error, pLog) << "Running ESPFIT" << std::flush;
    try {
      Esp2multipole esp2multipole = Esp2multipole(pLog);
      esp2multipole.Initialize(_esp_options);
      std::string ESPDIR =
          "MP_FILES/" + frame_dir + "/" + esp2multipole.GetStateString();
      StaticSegment seg2 = esp2multipole.Extractingcharges(orbitals);
      std::string mps_file = (format("%1%_%2%_%3%.mps") % segType % segId %
                              esp2multipole.GetStateString())
                                 .str();
      boost::filesystem::create_directories(ESPDIR);
      seg2.WriteMPS(ESPDIR + "/" + mps_file,
                    "Generated by eqm:" + esp2multipole.GetStateString());
      XTP_LOG(Log::error, pLog)
          << "Written charges to " << (ESPDIR + "/" + mps_file) << std::flush;
      segment_summary.add("partialcharges", (ESPDIR + "/" + mps_file));
    } catch (std::runtime_error& error) {
      std::string errormessage(error.what());
      SetJobToFailed(jres, pLog, "ESPFIT:" + errormessage);
      return jres;
    }
  }
  XTP_LOG(Log::error, pLog) << TimeStamp() << " Finished evaluating site "
                            << seg.getId() << std::flush;

  if (_do_dft_parse || _do_gwbse) {
    XTP_LOG(Log::error, pLog) << "Saving data to " << orb_file << std::flush;
    std::string DIR = eqm_work_dir + "/molecules/" + frame_dir;
    boost::filesystem::create_directories(DIR);
    std::string ORBFILE = DIR + "/" + orb_file;
    orbitals.WriteToCpt(ORBFILE);
  }

  // output of the JOB
  jres.setOutput(job_summary);
  jres.setStatus(Job::COMPLETE);

  return jres;
}
}  // namespace xtp
}  // namespace votca
<|endoftext|>


<commit_before>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2019-2021 Baldur Karlsson
 *
 * 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 "gl_test.h"

RD_TEST(GL_Simple_Triangle, OpenGLGraphicsTest)
{
  static constexpr const char *Description =
      "Just draws a simple triangle, using normal pipeline. Basic test that can be used "
      "for any dead-simple tests that don't require any particular API use";

  int main()
  {
    // initialise, create window, create context, etc
    if(!Init())
      return 3;

    GLuint vao = MakeVAO();
    glBindVertexArray(vao);

    GLuint vb = MakeBuffer();
    glBindBuffer(GL_ARRAY_BUFFER, vb);
    glBufferData(GL_ARRAY_BUFFER, sizeof(DefaultTri), DefaultTri, GL_STATIC_DRAW);

    ConfigureDefaultVAO();

    GLuint program = MakeProgram(GLDefaultVertex, GLDefaultPixel);

    // make a simple texture so that the structured data includes texture initial states
    GLuint tex = MakeTexture();
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 4, 4);

    float col[] = {0.8f, 0.2f, 0.9f, 1.0f};
    float textureColourData[4 * 4 * 4];
    for(auto i = 0; i < 4 * 4; ++i)
    {
      for(auto c = 0; c < 4; ++c)
        textureColourData[i * 4 + c] = col[c];
    }

    while(Running())
    {
      float col[] = {0.2f, 0.2f, 0.2f, 1.0f};
      glClearBufferfv(GL_COLOR, 0, col);

      glBindTexture(GL_TEXTURE_2D, tex);
      glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGBA, GL_FLOAT, textureColourData);

      glBindVertexArray(vao);

      glUseProgram(program);

      glViewport(0, 0, GLsizei(screenWidth), GLsizei(screenHeight));

      glDrawArrays(GL_TRIANGLES, 0, 3);

      Present();
    }

    return 0;
  }
};

REGISTER_TEST();
<commit_msg>Fix compile and code style errors in GL_Simple_Triangle<commit_after>/******************************************************************************
 * The MIT License (MIT)
 *
 * Copyright (c) 2019-2021 Baldur Karlsson
 *
 * 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 "gl_test.h"

RD_TEST(GL_Simple_Triangle, OpenGLGraphicsTest)
{
  static constexpr const char *Description =
      "Just draws a simple triangle, using normal pipeline. Basic test that can be used "
      "for any dead-simple tests that don't require any particular API use";

  int main()
  {
    // initialise, create window, create context, etc
    if(!Init())
      return 3;

    GLuint vao = MakeVAO();
    glBindVertexArray(vao);

    GLuint vb = MakeBuffer();
    glBindBuffer(GL_ARRAY_BUFFER, vb);
    glBufferData(GL_ARRAY_BUFFER, sizeof(DefaultTri), DefaultTri, GL_STATIC_DRAW);

    ConfigureDefaultVAO();

    GLuint program = MakeProgram(GLDefaultVertex, GLDefaultPixel);

    // make a simple texture so that the structured data includes texture initial states
    GLuint tex = MakeTexture();
    glBindTexture(GL_TEXTURE_2D, tex);
    glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, 4, 4);

    float col[] = {0.2f, 0.2f, 0.2f, 1.0f};
    float textureColourData[4 * 4 * 4];
    for(int i = 0; i < 4 * 4; ++i)
    {
      for(int c = 0; c < 4; ++c)
        textureColourData[i * 4 + c] = col[c];
    }

    while(Running())
    {
      glClearBufferfv(GL_COLOR, 0, col);

      glBindTexture(GL_TEXTURE_2D, tex);
      glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGBA, GL_FLOAT, textureColourData);

      glBindVertexArray(vao);

      glUseProgram(program);

      glViewport(0, 0, GLsizei(screenWidth), GLsizei(screenHeight));

      glDrawArrays(GL_TRIANGLES, 0, 3);

      Present();
    }

    return 0;
  }
};

REGISTER_TEST();
<|endoftext|>


<commit_before>/*
 * Copyright 2011 Intel Corporation.
 *
 * This program is licensed under the terms and conditions of the
 * Apache License, version 2.0.  The full text of the Apache License is at
 * http://www.apache.org/licenses/LICENSE-2.0
 */

#include "plugin.h"

#include "applicationsmodel.h"
#include "appupappsmodel.h"
#include "backgroundmodel.h"
#include "browserlistmodel.h"
#include "desktop.h"
#include "desktopdatabase.h"
#include "devicemodel.h"
#include "favoriteapplicationsmodel.h"
#include "gconfitem.h"
#include "imageextension.h"
#include "librarymodel.h"
#include "meegothemedimageprovider.h"
#include "paintspy.h"
#include "plugin.h"
#include "qmldebugtools.h"
#include "recentapplicationsmodel.h"
#include "relativetimestamp.h"
#include "roundeditem.h"
#include "speechbubbledialog.h"
#include "stricturl.h"
#include "systemiconprovider.h"
#include "timestampupdater.h"
#include "timezonelistmodel.h"
#include "translator.h"
#include "udisk_interface.h"
#include "valuespacepublisher.h"
#include "valuespacesubscriber.h"
#include "windowelement.h"
#include "windowiconprovider.h"
#include "windowinfo.h"
#include "windowlistener.h"
#include "windowmodel.h"

void MeeGoUxComponentsKernelPlugin::registerTypes(const char *uri)
{
    qmlRegisterType<TimezoneListModel>(uri, 0, 0, "TimezoneListModel");
    qmlRegisterType<RecentApplicationsModel>(uri,0,1, "RecentApplicationsModel");

    qmlRegisterType<AppUpAppsModel>(uri, 0, 1, "AppUpAppsModel");
    qmlRegisterType<FavoriteApplicationsModel>(uri,0,1, "FavoriteApplicationsModel");
    qmlRegisterType<ApplicationsModel>(uri, 0, 1, "ApplicationsModel");
    qmlRegisterType<WindowModel>(uri, 0, 1, "WindowModel");

    qmlRegisterInterface<Desktop>("Desktop");
    qmlRegisterInterface<WindowElement>("WindowElement");
    qmlRegisterType<devicemodel>(uri,0,1,"UDiskDeviceModel");

    qmlRegisterType<BrowserItemListModel>(uri,0,0,"BrowserItemListModel");

    qmlRegisterType<BackgroundModel>(uri, 0, 1, "BackgroundModel");

    qmlRegisterInterface<Desktop>("Desktop");
    qmlRegisterInterface<WindowElement>("WindowElement");

    qmlRegisterType<ImageExtension>(uri, 0,0, "ImageExtension");

    qmlRegisterType<ValueSpacePublisher>(uri, 0,0, "ValueSpacePublisher");
    qmlRegisterType<ValueSpaceSubscriber>(uri, 0,0,"ValueSpaceSubscriber");

    qmlRegisterType<RelativeTimeStamp>(uri, 0,1, "RelativeTimeStamp");

    qmlRegisterType<speechbubbledialog>(uri, 0, 1, "RectangularBubble");

    qmlRegisterType<RoundedItem>(uri,0,1,"RoundedItem");

    qmlRegisterType<Translator>(uri,0,0,"Translator");
    qmlRegisterType<QmlDebugTools>(uri, 0, 0, "QmlDebugTools");

    qmlRegisterType<PaintSpy>(uri, 0, 1, "PaintSpy");

    qmlRegisterType<GConfItem>(uri, 0, 1, "GConfItem");

    // qt bug workarounds
    qmlRegisterType<StrictUrl>(uri, 0, 1, "StrictUrl");
}

void MeeGoUxComponentsKernelPlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri)
{
    Q_UNUSED(uri);
}

Q_EXPORT_PLUGIN(MeeGoUxComponentsKernelPlugin);
<commit_msg>add imageprovider to the labs plugin<commit_after>/*
 * Copyright 2011 Intel Corporation.
 *
 * This program is licensed under the terms and conditions of the
 * Apache License, version 2.0.  The full text of the Apache License is at
 * http://www.apache.org/licenses/LICENSE-2.0
 */

#include "plugin.h"

#include "applicationsmodel.h"
#include "appupappsmodel.h"
#include "backgroundmodel.h"
#include "browserlistmodel.h"
#include "desktop.h"
#include "desktopdatabase.h"
#include "devicemodel.h"
#include "favoriteapplicationsmodel.h"
#include "gconfitem.h"
#include "imageextension.h"
#include "librarymodel.h"
#include "meegothemedimageprovider.h"
#include "paintspy.h"
#include "plugin.h"
#include "qmldebugtools.h"
#include "recentapplicationsmodel.h"
#include "relativetimestamp.h"
#include "roundeditem.h"
#include "speechbubbledialog.h"
#include "stricturl.h"
#include "systemiconprovider.h"
#include "timestampupdater.h"
#include "timezonelistmodel.h"
#include "translator.h"
#include "udisk_interface.h"
#include "valuespacepublisher.h"
#include "valuespacesubscriber.h"
#include "windowelement.h"
#include "windowiconprovider.h"
#include "windowinfo.h"
#include "windowlistener.h"
#include "windowmodel.h"

void MeeGoUxComponentsKernelPlugin::registerTypes(const char *uri)
{
    qmlRegisterType<TimezoneListModel>(uri, 0, 0, "TimezoneListModel");
    qmlRegisterType<RecentApplicationsModel>(uri,0,1, "RecentApplicationsModel");

    qmlRegisterType<AppUpAppsModel>(uri, 0, 1, "AppUpAppsModel");
    qmlRegisterType<FavoriteApplicationsModel>(uri,0,1, "FavoriteApplicationsModel");
    qmlRegisterType<ApplicationsModel>(uri, 0, 1, "ApplicationsModel");
    qmlRegisterType<WindowModel>(uri, 0, 1, "WindowModel");

    qmlRegisterInterface<Desktop>("Desktop");
    qmlRegisterInterface<WindowElement>("WindowElement");
    qmlRegisterType<devicemodel>(uri,0,1,"UDiskDeviceModel");

    qmlRegisterType<BrowserItemListModel>(uri,0,0,"BrowserItemListModel");

    qmlRegisterType<BackgroundModel>(uri, 0, 1, "BackgroundModel");

    qmlRegisterInterface<Desktop>("Desktop");
    qmlRegisterInterface<WindowElement>("WindowElement");

    qmlRegisterType<ImageExtension>(uri, 0,0, "ImageExtension");

    qmlRegisterType<ValueSpacePublisher>(uri, 0,0, "ValueSpacePublisher");
    qmlRegisterType<ValueSpaceSubscriber>(uri, 0,0,"ValueSpaceSubscriber");

    qmlRegisterType<RelativeTimeStamp>(uri, 0,1, "RelativeTimeStamp");

    qmlRegisterType<speechbubbledialog>(uri, 0, 1, "RectangularBubble");

    qmlRegisterType<RoundedItem>(uri,0,1,"RoundedItem");

    qmlRegisterType<Translator>(uri,0,0,"Translator");
    qmlRegisterType<QmlDebugTools>(uri, 0, 0, "QmlDebugTools");

    qmlRegisterType<PaintSpy>(uri, 0, 1, "PaintSpy");

    qmlRegisterType<GConfItem>(uri, 0, 1, "GConfItem");

    // qt bug workarounds
    qmlRegisterType<StrictUrl>(uri, 0, 1, "StrictUrl");
}

void MeeGoUxComponentsKernelPlugin::initializeEngine(QDeclarativeEngine *engine, const char *uri)
{
    engine->addImageProvider("systemicon", new SystemIconProvider);
    engine->addImageProvider("meegoimage", new MeeGoThemedImageProvider);
    engine->addImageProvider("windowicon", new WindowIconProvider);
    Q_UNUSED(uri);
}

Q_EXPORT_PLUGIN(MeeGoUxComponentsKernelPlugin);
<|endoftext|>


<commit_before>/*
Copyright (c) 2012 Carsten Burstedde, Donna Calhoun
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include "fclaw2d_convenience.h"
#include "amr_forestclaw.H"

int
main (int argc, char **argv)
{
  int			mpiret;
  int			lp;
  MPI_Comm		mpicomm;
  fclaw2d_domain_t	*domain;

  mpiret = MPI_Init (&argc, &argv);
  SC_CHECK_MPI (mpiret);
  mpicomm = MPI_COMM_WORLD;
  lp = SC_LP_PRODUCTION;

  sc_init (mpicomm, 0, 0, NULL, lp);
  p4est_init (NULL, lp);

  domain = fclaw2d_domain_new_unitsquare (mpicomm);

  fclaw2d_domain_count_levels (domain, lp);

  amrsetup(domain);
  amrinit(domain);
  amrrun(domain);
  amrreset (domain);

  fclaw2d_domain_destroy (domain);

  sc_finalize ();

  mpiret = MPI_Finalize ();
  SC_CHECK_MPI (mpiret);

  return 0;
}
<commit_msg>example1.cpp is now 'swirl.cpp', under applications/advection/2d/swirl<commit_after><|endoftext|>


<commit_before>/*******************************************************************************
 * example2.cpp
 * Measure time to write to containers in one of 2 modes:
 * 1.  using the standard STL allocator
 * 2.  using ArenaAlloc
 *
 * This software is distributed under the terms of the MIT license.
 * Don't panic!!!! Share and enjoy.
 *****************************************************************************/
#include <thread>
#include <condition_variable>
#include <mutex>
#include <chrono>
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include "arenaalloc.h"
#include "recyclealloc.h"

// As promised in example1.cpp, this example requires c++11

// compile as: g++ -O2 -DARENA_ALLOCATOR_TEST -std=c++11 -o example2-arena example2.cpp -lpthread
// to test the arena allocator logic

// compile as: g++ -O2 -std=c++11 -o example2-stdalloc example2.cpp -lpthread
// to test the standard allocator.

// If tcmalloc is available try this also:
// g++ -O2 -std=c++11 -fno-builtin-malloc -o example2-stdtcmalloc example2.cpp -ltcmalloc -lpthread
// g++ -O2 -DARENA_ALLOCATOR_TEST -std=c++11 -fno-builtin-malloc -o example2-arenatcmalloc example2.cpp -ltcmalloc -lpthread

// In my testing of this not perfectly scientific example, the standard allocator + tcmalloc was faster by
// a little bit over the arena allocator with the standard malloc.  Both of those were significantly
// faster than the standard allocator with the standard malloc.  I kept getting a core dump when
// running the arena allocator with tcmalloc so I cannot present results on that.  Give it a try though.
// It's possible there may be a problem in how my code is structured for tcmalloc to work with the arena allocator.

typedef std::chrono::high_resolution_clock::time_point hres_t;
typedef std::chrono::duration<size_t, std::ratio<1,1000000> > duration_t; // duration in micro-seconds

struct task
{
  std::mutex& m_mutexRef;
  std::condition_variable& m_condVarRef;
  bool& m_run;

  task( std::mutex& m, std::condition_variable& condVar, bool& runVar ):
    m_mutexRef( m ),
    m_run( runVar ),
    m_condVarRef( condVar )
  {
  }

  void  operator()()
  {

    // barrier synchronize the threads as much as possible to start them as close as possible
    // to the same time.
    {
      std::unique_lock<std::mutex> lk( m_mutexRef );
      std::cout << "Thread=" << std::this_thread::get_id() << " is waiting..." << std::endl;
      m_condVarRef.wait( lk, [this] { return m_run == true; }  ); // wait until the lambda condition is true
    }

    hres_t start = std::chrono::high_resolution_clock::now();

    // do map insert
    doWork();

    hres_t end = std::chrono::high_resolution_clock::now();
    duration_t timespan =  std::chrono::duration_cast< duration_t >( end - start );

    {
      // report timing results w/ lock held so that the output isn't all munged
      std::lock_guard<std::mutex> lg( m_mutexRef );
      std::cout << "threadid: " << std::this_thread::get_id() << " clicks: " << timespan.count() << std::endl;
    }
  }

  void doWork()
  {

    // insert a million values into a map<int,strtype> using the specified map type
#if defined (ARENA_ALLOCATOR_TEST)
    typedef std::basic_string<char, std::char_traits<char>, ArenaAlloc::Alloc<char> > strtype;
    ArenaAlloc::Alloc< char > charAllocator( 65536 );
    strtype answerToEverything( "42", charAllocator );

    ArenaAlloc::Alloc< std::pair< const int, strtype > > alloc( 65536 );
    std::map< int, strtype , std::less<int>, ArenaAlloc::Alloc<std::pair<const int,strtype> > > intToStrMap( std::less<int>(), alloc );
#elif defined(RECYCLE_ALLOCATOR_TEST)
    typedef std::basic_string<char, std::char_traits<char>, ArenaAlloc::RecycleAlloc<char> > strtype;
    ArenaAlloc::RecycleAlloc< char > charAllocator( 65536 );
    strtype answerToEverything( "42", charAllocator );

    ArenaAlloc::RecycleAlloc< std::pair< const int, strtype > > alloc( 65536 );
    std::map< int, strtype , std::less<int>, ArenaAlloc::RecycleAlloc<std::pair<const int,strtype> > >
      intToStrMap( std::less<int>(), alloc );
#else
    typedef std::string strtype;
    std::map<int, strtype> intToStrMap;
    std::string answerToEverything( "42" );
#endif

    for( int i = 0; i < 10000000; i++ )
    {
      intToStrMap.insert( std::pair< const int, strtype >( i, answerToEverything ) ); // The answer to everything

      if( i > 10 && ( i % 5 == 0 ) )
	intToStrMap.erase( i - 5 ); // to provide some re-use for for testing the recycle allocator
    }

    // Note: time to clear allocator is included in the runtime.
  }

};

int main()
{

  size_t concurrency = std::thread::hardware_concurrency();
  std::cout << "Running with " << concurrency << " threads" << std::endl;

  std::vector< std::thread > threads;

  std::mutex m;
  std::condition_variable cv;
  bool runBool = false;

  for( size_t i = 0; i < concurrency; i++ )
  {
    task t( m, cv, runBool );
    threads.push_back( std::thread( t ) );
  }

  std::cout << "Waiting a bit before waking the stalled threads" << std::endl;
  std::this_thread::sleep_for( std::chrono::seconds( 5 ) );

  std::cout << "And they're off...!" << std::endl;
  runBool = true;
  cv.notify_all();

  std::for_each( threads.begin(), threads.end(), std::mem_fn( &std::thread::join ) );
  return 0;
}
<commit_msg>track bytes allocated in the test<commit_after>/*******************************************************************************
 * example2.cpp
 * Measure time to write to containers in one of 2 modes:
 * 1.  using the standard STL allocator
 * 2.  using ArenaAlloc
 *
 * This software is distributed under the terms of the MIT license.
 * Don't panic!!!! Share and enjoy.
 *****************************************************************************/
#include <thread>
#include <condition_variable>
#include <mutex>
#include <chrono>
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include "arenaalloc.h"
#include "recyclealloc.h"

// As promised in example1.cpp, this example requires c++11

// compile as: g++ -O2 -DARENA_ALLOCATOR_TEST -std=c++11 -o example2-arena example2.cpp -lpthread
// to test the arena allocator logic

// compile as: g++ -O2 -std=c++11 -o example2-stdalloc example2.cpp -lpthread
// to test the standard allocator.

// If tcmalloc is available try this also:
// g++ -O2 -std=c++11 -fno-builtin-malloc -o example2-stdtcmalloc example2.cpp -ltcmalloc -lpthread
// g++ -O2 -DARENA_ALLOCATOR_TEST -std=c++11 -fno-builtin-malloc -o example2-arenatcmalloc example2.cpp -ltcmalloc -lpthread

// In my testing of this not perfectly scientific example, the standard allocator + tcmalloc was faster by
// a little bit over the arena allocator with the standard malloc.  Both of those were significantly
// faster than the standard allocator with the standard malloc.  I kept getting a core dump when
// running the arena allocator with tcmalloc so I cannot present results on that.  Give it a try though.
// It's possible there may be a problem in how my code is structured for tcmalloc to work with the arena allocator.

typedef std::chrono::high_resolution_clock::time_point hres_t;
typedef std::chrono::duration<size_t, std::ratio<1,1000000> > duration_t; // duration in micro-seconds

struct task
{
  std::mutex& m_mutexRef;
  std::condition_variable& m_condVarRef;
  bool& m_run;

  task( std::mutex& m, std::condition_variable& condVar, bool& runVar ):
    m_mutexRef( m ),
    m_run( runVar ),
    m_condVarRef( condVar )
  {
  }

  void  operator()()
  {

    // barrier synchronize the threads as much as possible to start them as close as possible
    // to the same time.
    {
      std::unique_lock<std::mutex> lk( m_mutexRef );
      std::cout << "Thread=" << std::this_thread::get_id() << " is waiting..." << std::endl;
      m_condVarRef.wait( lk, [this] { return m_run == true; }  ); // wait until the lambda condition is true
    }

    hres_t start = std::chrono::high_resolution_clock::now();

    // do map insert / delete
    std::size_t numBytesAllocated = doWork();

    hres_t end = std::chrono::high_resolution_clock::now();
    duration_t timespan =  std::chrono::duration_cast< duration_t >( end - start );

    {
      // report timing results w/ lock held so that the output isn't all munged
      std::lock_guard<std::mutex> lg( m_mutexRef );
      std::cout << "threadid: " << std::this_thread::get_id() << " clicks: " << timespan.count();
      std::cout << " bytes allocated: " << numBytesAllocated << std::endl;
    }
  }

  std::size_t doWork()
  {

    // insert a million values into a map<int,strtype> using the specified map type
#if defined (ARENA_ALLOCATOR_TEST)
    typedef std::basic_string<char, std::char_traits<char>, ArenaAlloc::Alloc<char> > strtype;
    ArenaAlloc::Alloc< char > charAllocator( 65536 );
    strtype answerToEverything( "42", charAllocator );

    ArenaAlloc::Alloc< std::pair< const int, strtype > > alloc( 65536 );
    std::map< int, strtype , std::less<int>, ArenaAlloc::Alloc<std::pair<const int,strtype> > > intToStrMap( std::less<int>(), alloc );
#elif defined(RECYCLE_ALLOCATOR_TEST)
    typedef std::basic_string<char, std::char_traits<char>, ArenaAlloc::RecycleAlloc<char> > strtype;
    ArenaAlloc::RecycleAlloc< char > charAllocator( 65536 );
    strtype answerToEverything( "42", charAllocator );

    ArenaAlloc::RecycleAlloc< std::pair< const int, strtype > > alloc( 65536 );
    std::map< int, strtype , std::less<int>, ArenaAlloc::RecycleAlloc<std::pair<const int,strtype> > >
      intToStrMap( std::less<int>(), alloc );
#else
    typedef std::string strtype;
    std::map<int, strtype> intToStrMap;
    std::string answerToEverything( "42" );
#endif

    for( int i = 0; i < 10000000; i++ )
    {
      intToStrMap.insert( std::pair< const int, strtype >( i, answerToEverything ) ); // The answer to everything

      if( i > 10 && ( i % 5 == 0 ) )
	intToStrMap.erase( i - 5 ); // to provide some re-use for for testing the recycle allocator
    }

    // Note: time to clear allocator is included in the runtime.
    return charAllocator.getNumBytesAllocated() + alloc.getNumBytesAllocated();
  }

};

int main()
{

  size_t concurrency = std::thread::hardware_concurrency();
  std::cout << "Running with " << concurrency << " threads" << std::endl;

  std::vector< std::thread > threads;

  std::mutex m;
  std::condition_variable cv;
  bool runBool = false;

  for( size_t i = 0; i < concurrency; i++ )
  {
    task t( m, cv, runBool );
    threads.push_back( std::thread( t ) );
  }

  std::cout << "Waiting a bit before waking the stalled threads" << std::endl;
  std::this_thread::sleep_for( std::chrono::seconds( 5 ) );

  std::cout << "And they're off...!" << std::endl;
  runBool = true;
  cv.notify_all();

  std::for_each( threads.begin(), threads.end(), std::mem_fn( &std::thread::join ) );
  return 0;
}
<|endoftext|>