<commit_before>
#ifndef ROPUFU_SETTLERS_ONLINE_BLACK_MARSH_TURTLE_HPP_INCLUDED
#define ROPUFU_SETTLERS_ONLINE_BLACK_MARSH_TURTLE_HPP_INCLUDED

#include <aftermath/not_an_error.hpp>
#include <aftermath/probability.hpp>
#include <nlohmann/json.hpp>

#include "config.hpp"

#include "../settlers_online/unit_database.hpp"
#include "../settlers_online/army_parser.hpp"
#include "../settlers_online/army.hpp"
#include "../settlers_online/army_decorator.hpp"
#include "../settlers_online/battle_skill.hpp"
#include "../settlers_online/binomial_pool.hpp"
#include "../settlers_online/camp.hpp"
#include "../settlers_online/char_string.hpp"
#include "../settlers_online/combat_mechanics.hpp"
#include "../settlers_online/combat_result.hpp"
#include "../settlers_online/conditioned_army.hpp"
#include "../settlers_online/randomized_attack_sequence.hpp"
#include "../settlers_online/report_entry.hpp"
#include "../settlers_online/trivial_attack_sequence.hpp"
#include "../settlers_online/unit_faction.hpp"
#include "../settlers_online/unit_group.hpp"
#include "../settlers_online/unit_type.hpp"
#include "../settlers_online/warnings.hpp"

#include <chrono> // std::chrono::steady_clock, std::chrono::duration_cast
#include <cstddef> // std::size_t
#include <cstdint> // std::int32_t
#include <map> // std::map
#include <set> // std::set
#include <string> // std::string, std::to_string
#include <vector> // std::vector

namespace ropufu
{
    namespace settlers_online
    {
        namespace black_marsh
        {
            /** The main struct of the simulator. Responsible for handling parsing / construction / simulations / etc. */
            struct turtle
            {
                using type = turtle;

                using sequencer_type = randomized_attack_sequence<>;
                using sequencer_type_low = trivial_attack_sequence<false>;
                using sequencer_type_high = trivial_attack_sequence<true>;

                using empirical_measure = aftermath::probability::empirical_measure<std::size_t, std::size_t, double>;

                static bool is_config_valid() noexcept
                {
                    config& c = config::instance();
                    if (!c.good()) return false;
                    return true;
                } // is_config_valid(...)

                template <typename t_action_type>
                static double elapsed_seconds(t_action_type action) noexcept
                {
                    std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
                    action();
                    std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();

                    double elapsed_seconds = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() / 1'000.0;
                    return elapsed_seconds;
                } // elapsed_seconds(...)

                static void present_losses(std::vector<report_entry>& report, const army& a, const std::vector<empirical_measure>& losses) noexcept
                {
                    for (std::size_t k = 0; k < a.count_groups(); k++)
                    {
                        report_entry entry(a[k], losses[k]);
                        entry.set_text("Losses in " + a[k].unit().names().front());
                        report.push_back(entry);
                    }
                } // present_losses(...)

            private:
                settlers_online::warnings m_warnings = { };
                army m_left = { };
                army m_right = { };

            public:
                turtle() noexcept
                {
                    this->reload();
                } // turtle(...)

                void reload() noexcept
                {
                    config& c = config::instance();
                    unit_database& db = unit_database::instance();

                    c.read();
                    if (!c.good())
                    {
                        this->m_warnings.push_back("Failed to read config file.");
                        return;
                    }

                    // ~~ Build unit database ~~
                    std::size_t count_units = db.load_from_folder(c.maps_path());
                    this->m_warnings.push_back("Loaded " + std::to_string(count_units) + " units.");
                    this->m_left = { };
                    this->m_right = { };
                } // reload(...)

                const settlers_online::warnings& warnings() const noexcept { return this->m_warnings; }
                settlers_online::warnings& warnings() noexcept { return this->m_warnings; }

                const army& left() const noexcept { return this->m_left; }
                const army& right() const noexcept { return this->m_right; }

                void parse_left(const std::string& army_string) noexcept
                {
                    army_parser parser = army_string;
                    this->m_left = parser.build(this->m_warnings, true, true, false);
                } // parse_left(...)

                void parse_right(const std::string& army_string) noexcept
                {
                    army_parser parser = army_string;
                    this->m_right = parser.build(this->m_warnings);
                } // parse_right(...)

                std::vector<report_entry> log() noexcept { return this->run(true); }

                std::vector<report_entry> run(bool is_log = false) noexcept
                {
                    std::vector<report_entry> report { };

                    const config& c = config::instance();
                    if (this->m_left.count_groups() == 0 || this->m_right.count_groups() == 0)
                    {
                        this->m_warnings.push_back("Armies (left and right) have to be set prior to execution.");
                        return report;
                    }

                    settlers_online::warnings left_decorator_warnings { };
                    settlers_online::warnings right_decorator_warnings { };
                    c.left().decorate(this->m_left, left_decorator_warnings);
                    c.right().decorate(this->m_right, right_decorator_warnings);

                    // ~~ Combat phase ~~
                    ropufu::settlers_online::combat_mechanics combat(this->m_left, this->m_right);
                    ropufu::settlers_online::combat_mechanics snapshot = combat;

                    //std::cout << "Building left cache..." << std::endl;
                    sequencer_type::pool_type::instance().cache(combat.left().underlying());
                    //std::cout << "Building right cache..." << std::endl;
                    sequencer_type::pool_type::instance().cache(combat.right().underlying());

                    auto army_format = [] (const unit_type& u) { return " " + u.names().front(); };
                    std::string left_army_string = this->m_left.to_string(army_format);
                    std::string right_army_string = this->m_right.to_string(army_format);

                    // ~~ Choose sequencers ~~
                    sequencer_type left_seq { };
                    sequencer_type right_seq { };

                    report.emplace_back(left_army_string + " vs. " + right_army_string);
                    if (is_log)
                    {
                        combat.set_do_log(true);
                        combat.execute(left_seq, right_seq);
                        return report;
                    }

                    empirical_measure rounds { };
                    std::vector<empirical_measure> left_losses(this->m_left.count_groups());
                    std::vector<empirical_measure> right_losses(this->m_right.count_groups());
                    for (std::size_t i = 0; i < c.simulation_count(); ++i)
                    {
                        std::size_t combat_rounds = combat.execute(left_seq, right_seq);
                        //const ropufu::settlers_online::combat_result& result = combat.outcome();

                        std::vector<std::size_t> x = combat.left().calculate_losses();
                        std::vector<std::size_t> y = combat.right().calculate_losses();
                        for (std::size_t k = 0; k < x.size(); k++) left_losses[k].observe(x[k]);
                        for (std::size_t k = 0; k < y.size(); k++) right_losses[k].observe(y[k]);

                        for (std::size_t j = 0; j < c.destruction_count(); ++j)
                        {
                            std::size_t destruction_rounds = combat.destruct(left_seq, right_seq);
                            rounds.observe(combat_rounds + destruction_rounds);
                        }
                        combat = snapshot;
                    }

                    report.emplace_back("Rounds", rounds);

                    report.emplace_back("Left army", left_army_string);
                    if (!left_decorator_warnings.empty()) left_decorator_warnings.unwind([&] (const std::string& w) { report.emplace_back("Skills", w); });
                    type::present_losses(report, this->m_left, left_losses);

                    report.emplace_back("Right army", left_army_string);
                    if (!right_decorator_warnings.empty()) right_decorator_warnings.unwind([&] (const std::string& w) { report.emplace_back("Skills", w); });
                    type::present_losses(report, this->m_right, right_losses);

                    c.to_cbor(report);
                    return report;
                } // run(...)
            }; // struct turtle
        } // namespace black_marsh
    } // namespace settlers_online
} // namespace ropufu

#endif // ROPUFU_SETTLERS_ONLINE_BLACK_MARSH_TURTLE_HPP_INCLUDED
<commit_msg>Fixed report entry typo.<commit_after>
#ifndef ROPUFU_SETTLERS_ONLINE_BLACK_MARSH_TURTLE_HPP_INCLUDED
#define ROPUFU_SETTLERS_ONLINE_BLACK_MARSH_TURTLE_HPP_INCLUDED

#include <aftermath/not_an_error.hpp>
#include <aftermath/probability.hpp>
#include <nlohmann/json.hpp>

#include "config.hpp"

#include "../settlers_online/unit_database.hpp"
#include "../settlers_online/army_parser.hpp"
#include "../settlers_online/army.hpp"
#include "../settlers_online/army_decorator.hpp"
#include "../settlers_online/battle_skill.hpp"
#include "../settlers_online/binomial_pool.hpp"
#include "../settlers_online/camp.hpp"
#include "../settlers_online/char_string.hpp"
#include "../settlers_online/combat_mechanics.hpp"
#include "../settlers_online/combat_result.hpp"
#include "../settlers_online/conditioned_army.hpp"
#include "../settlers_online/randomized_attack_sequence.hpp"
#include "../settlers_online/report_entry.hpp"
#include "../settlers_online/trivial_attack_sequence.hpp"
#include "../settlers_online/unit_faction.hpp"
#include "../settlers_online/unit_group.hpp"
#include "../settlers_online/unit_type.hpp"
#include "../settlers_online/warnings.hpp"

#include <chrono> // std::chrono::steady_clock, std::chrono::duration_cast
#include <cstddef> // std::size_t
#include <cstdint> // std::int32_t
#include <map> // std::map
#include <set> // std::set
#include <string> // std::string, std::to_string
#include <vector> // std::vector

namespace ropufu
{
    namespace settlers_online
    {
        namespace black_marsh
        {
            /** The main struct of the simulator. Responsible for handling parsing / construction / simulations / etc. */
            struct turtle
            {
                using type = turtle;

                using sequencer_type = randomized_attack_sequence<>;
                using sequencer_type_low = trivial_attack_sequence<false>;
                using sequencer_type_high = trivial_attack_sequence<true>;

                using empirical_measure = aftermath::probability::empirical_measure<std::size_t, std::size_t, double>;

                static bool is_config_valid() noexcept
                {
                    config& c = config::instance();
                    if (!c.good()) return false;
                    return true;
                } // is_config_valid(...)

                template <typename t_action_type>
                static double elapsed_seconds(t_action_type action) noexcept
                {
                    std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
                    action();
                    std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();

                    double elapsed_seconds = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() / 1'000.0;
                    return elapsed_seconds;
                } // elapsed_seconds(...)

                static void present_losses(std::vector<report_entry>& report, const army& a, const std::vector<empirical_measure>& losses) noexcept
                {
                    for (std::size_t k = 0; k < a.count_groups(); k++)
                    {
                        report_entry entry(a[k], losses[k]);
                        entry.set_text("Losses in " + a[k].unit().names().front());
                        report.push_back(entry);
                    }
                } // present_losses(...)

            private:
                settlers_online::warnings m_warnings = { };
                army m_left = { };
                army m_right = { };

            public:
                turtle() noexcept
                {
                    this->reload();
                } // turtle(...)

                void reload() noexcept
                {
                    config& c = config::instance();
                    unit_database& db = unit_database::instance();

                    c.read();
                    if (!c.good())
                    {
                        this->m_warnings.push_back("Failed to read config file.");
                        return;
                    }

                    // ~~ Build unit database ~~
                    std::size_t count_units = db.load_from_folder(c.maps_path());
                    this->m_warnings.push_back("Loaded " + std::to_string(count_units) + " units.");
                    this->m_left = { };
                    this->m_right = { };
                } // reload(...)

                const settlers_online::warnings& warnings() const noexcept { return this->m_warnings; }
                settlers_online::warnings& warnings() noexcept { return this->m_warnings; }

                const army& left() const noexcept { return this->m_left; }
                const army& right() const noexcept { return this->m_right; }

                void parse_left(const std::string& army_string) noexcept
                {
                    army_parser parser = army_string;
                    this->m_left = parser.build(this->m_warnings, true, true, false);
                } // parse_left(...)

                void parse_right(const std::string& army_string) noexcept
                {
                    army_parser parser = army_string;
                    this->m_right = parser.build(this->m_warnings);
                } // parse_right(...)

                std::vector<report_entry> log() noexcept { return this->run(true); }

                std::vector<report_entry> run(bool is_log = false) noexcept
                {
                    std::vector<report_entry> report { };

                    const config& c = config::instance();
                    if (this->m_left.count_groups() == 0 || this->m_right.count_groups() == 0)
                    {
                        this->m_warnings.push_back("Armies (left and right) have to be set prior to execution.");
                        return report;
                    }

                    settlers_online::warnings left_decorator_warnings { };
                    settlers_online::warnings right_decorator_warnings { };
                    c.left().decorate(this->m_left, left_decorator_warnings);
                    c.right().decorate(this->m_right, right_decorator_warnings);

                    // ~~ Combat phase ~~
                    ropufu::settlers_online::combat_mechanics combat(this->m_left, this->m_right);
                    ropufu::settlers_online::combat_mechanics snapshot = combat;

                    //std::cout << "Building left cache..." << std::endl;
                    sequencer_type::pool_type::instance().cache(combat.left().underlying());
                    //std::cout << "Building right cache..." << std::endl;
                    sequencer_type::pool_type::instance().cache(combat.right().underlying());

                    auto army_format = [] (const unit_type& u) { return " " + u.names().front(); };
                    std::string left_army_string = this->m_left.to_string(army_format);
                    std::string right_army_string = this->m_right.to_string(army_format);

                    // ~~ Choose sequencers ~~
                    sequencer_type left_seq { };
                    sequencer_type right_seq { };

                    report.emplace_back(left_army_string + " vs. " + right_army_string);
                    if (is_log)
                    {
                        combat.set_do_log(true);
                        combat.execute(left_seq, right_seq);
                        return report;
                    }

                    empirical_measure rounds { };
                    std::vector<empirical_measure> left_losses(this->m_left.count_groups());
                    std::vector<empirical_measure> right_losses(this->m_right.count_groups());
                    for (std::size_t i = 0; i < c.simulation_count(); ++i)
                    {
                        std::size_t combat_rounds = combat.execute(left_seq, right_seq);
                        //const ropufu::settlers_online::combat_result& result = combat.outcome();

                        std::vector<std::size_t> x = combat.left().calculate_losses();
                        std::vector<std::size_t> y = combat.right().calculate_losses();
                        for (std::size_t k = 0; k < x.size(); k++) left_losses[k].observe(x[k]);
                        for (std::size_t k = 0; k < y.size(); k++) right_losses[k].observe(y[k]);

                        for (std::size_t j = 0; j < c.destruction_count(); ++j)
                        {
                            std::size_t destruction_rounds = combat.destruct(left_seq, right_seq);
                            rounds.observe(combat_rounds + destruction_rounds);
                        }
                        combat = snapshot;
                    }

                    report.emplace_back("Rounds", rounds);

                    report.emplace_back("Left army", left_army_string);
                    if (!left_decorator_warnings.empty()) left_decorator_warnings.unwind([&] (const std::string& w) { report.emplace_back("Skills", w); });
                    type::present_losses(report, this->m_left, left_losses);

                    report.emplace_back("Right army", right_army_string);
                    if (!right_decorator_warnings.empty()) right_decorator_warnings.unwind([&] (const std::string& w) { report.emplace_back("Skills", w); });
                    type::present_losses(report, this->m_right, right_losses);

                    c.to_cbor(report);
                    return report;
                } // run(...)
            }; // struct turtle
        } // namespace black_marsh
    } // namespace settlers_online
} // namespace ropufu

#endif // ROPUFU_SETTLERS_ONLINE_BLACK_MARSH_TURTLE_HPP_INCLUDED
<|endoftext|>


<commit_before>/* Copyright (c) 2011, NEC Europe Ltd, Consorzio Nazionale
 * Interuniversitario per le Telecomunicazioni, Institut
 * Telecom/Telecom Bretagne, ETH Zürich, INVEA-TECH a.s. 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 names of NEC Europe Ltd, Consorzio Nazionale
 *      Interuniversitario per le Telecomunicazioni, Institut Telecom/Telecom
 *      Bretagne, ETH Zürich, INVEA-TECH a.s. 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 <COPYRIGHT
 * HOLDERBE 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
 */

/*
 * <blockinfo type="FlowPrinter" invocation="direct, indirect" thread_exclusive="False">
 *   <humandesc>
 *   Receives a Flow message and prints its associated information (as returned
 *   by the methods in the Flow class)
 *   </humandesc>
 *
 *   <shortdesc>Prints meta-information regarding a flow</shortdesc>
 *
 *   <gates>
 *     <gate type="input" name="in_flow" msg_type="Flow" m_start="0" m_end="0" />
 *   </gates>
 *
 *   <paramsschema>
 *    element params {
 *      }
 *   </paramsschema>
 *
 *   <paramsexample>
 *     <params>
 *     </params>
 *   </paramsexample>
 *
 *   <variables>
 *   </variables>
 *
 * </blockinfo>
 */
#include <Block.hpp>
#include <BlockFactory.hpp>
#include <Flow.hpp>
#include <ClassId.hpp>
#include <arpa/inet.h>
#include <sstream>

namespace blockmon
{

    class FlowPrinter: public Block
    {
    /*
     * simple helper function to print an ip address
     * implemented by using inet_ntop.
     */
        static std::string ip_to_string(uint32_t ip)
        {

            char addr_buffer[INET_ADDRSTRLEN];
            //inet_ntop expects network byte order
            uint32_t flipped_ip=htonl(ip);

            if(!inet_ntop(AF_INET, &flipped_ip, addr_buffer, INET_ADDRSTRLEN))
                throw std::runtime_error("cannot convert ip address");
            return std::string (addr_buffer);
        }

    public:

        /*
         * constructor
         */
        FlowPrinter(const std::string &name, invocation_type invocation)
        : Block(name, invocation),
          m_ingate_id(register_input_gate("in_flow"))
        {
        }

        FlowPrinter(const FlowPrinter &)=delete;
        FlowPrinter& operator=(const FlowPrinter &) = delete;
        FlowPrinter(FlowPrinter &&)=delete;
        FlowPrinter& operator=(FlowPrinter &&) = delete;

        /*
         * destructor
         */
        virtual ~FlowPrinter()
        {}

        /*
         * this block takes no configuration parameters
         */
        virtual void _configure(const pugi::xml_node&  /*n*/ )
        {}

        /*
         * the main method
         * receives a Flow message and prints out its associated information
         * If the message belongs to another class, an exception is thrown.
         */
        virtual void _receive_msg(std::shared_ptr<const Msg>&& m, int /* index */)
        {
            if ( m->type() == MSG_ID(Flow) )
            {
                auto flow = static_cast<const Flow *>(m.get());
                std::stringstream ss;
                const FlowKey& fk = flow->key();
                int duration = flow->end_time() - flow->start_time();
                ss<<"packets="<<flow->packets() << ",";
                ss<<"bytes="<<flow->bytes() << ",";
                ss<<"start="<<flow->start_time() << ",";
                ss<<"end="<<flow->end_time() << ",";
                ss<<"duration.ms="<<duration<< ",";
                ss<<"source.ip4="<<ip_to_string(fk.src_ip4)<< ",";
                ss<<"source.port="<<fk.src_port<< ",";
                ss<<"destination.ip4="<<ip_to_string(fk.dst_ip4)<< ",";
                ss<<"destination.port="<<fk.dst_port;
                /*
                ss<<"Flow of  "<< flow->packets() << " packets and "<<flow->bytes()<<" bytes begin at "<<flow->start_time()<<" end at "<<flow->end_time()<< "duration (ms.) "<<duration <<std::endl;
                ss<<"SRC IP "<<ip_to_string(fk.src_ip4)<<" SRC port "<<fk.src_port<<std::endl;
                ss<<"DST IP "<<ip_to_string(fk.dst_ip4)<<" DST port "<<fk.dst_port<<std::endl;
                //ss<<"protocol "<<fk.proto<<std::endl;
                */
                blocklog(ss.str(),log_info);

            }
                else
            {
                throw std::runtime_error("Flowprinter: wrong message type");
            }
        }

    private:

        int m_ingate_id;

    };

#ifndef _BLOCKMON_DOXYGEN_SKIP_
    REGISTER_BLOCK(FlowPrinter,"FlowPrinter");
#endif /* _BLOCKMON_DOXYGEN_SKIP_ */
}

<commit_msg>FlowPrinter: duration in us not ms<commit_after>/* Copyright (c) 2011, NEC Europe Ltd, Consorzio Nazionale
 * Interuniversitario per le Telecomunicazioni, Institut
 * Telecom/Telecom Bretagne, ETH Zürich, INVEA-TECH a.s. 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 names of NEC Europe Ltd, Consorzio Nazionale
 *      Interuniversitario per le Telecomunicazioni, Institut Telecom/Telecom
 *      Bretagne, ETH Zürich, INVEA-TECH a.s. 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 <COPYRIGHT
 * HOLDERBE 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
 */

/*
 * <blockinfo type="FlowPrinter" invocation="direct, indirect" thread_exclusive="False">
 *   <humandesc>
 *   Receives a Flow message and prints its associated information (as returned
 *   by the methods in the Flow class)
 *   </humandesc>
 *
 *   <shortdesc>Prints meta-information regarding a flow</shortdesc>
 *
 *   <gates>
 *     <gate type="input" name="in_flow" msg_type="Flow" m_start="0" m_end="0" />
 *   </gates>
 *
 *   <paramsschema>
 *    element params {
 *      }
 *   </paramsschema>
 *
 *   <paramsexample>
 *     <params>
 *     </params>
 *   </paramsexample>
 *
 *   <variables>
 *   </variables>
 *
 * </blockinfo>
 */
#include <Block.hpp>
#include <BlockFactory.hpp>
#include <Flow.hpp>
#include <ClassId.hpp>
#include <arpa/inet.h>
#include <sstream>

namespace blockmon
{

    class FlowPrinter: public Block
    {
    /*
     * simple helper function to print an ip address
     * implemented by using inet_ntop.
     */
        static std::string ip_to_string(uint32_t ip)
        {

            char addr_buffer[INET_ADDRSTRLEN];
            //inet_ntop expects network byte order
            uint32_t flipped_ip=htonl(ip);

            if(!inet_ntop(AF_INET, &flipped_ip, addr_buffer, INET_ADDRSTRLEN))
                throw std::runtime_error("cannot convert ip address");
            return std::string (addr_buffer);
        }

    public:

        /*
         * constructor
         */
        FlowPrinter(const std::string &name, invocation_type invocation)
        : Block(name, invocation),
          m_ingate_id(register_input_gate("in_flow"))
        {
        }

        FlowPrinter(const FlowPrinter &)=delete;
        FlowPrinter& operator=(const FlowPrinter &) = delete;
        FlowPrinter(FlowPrinter &&)=delete;
        FlowPrinter& operator=(FlowPrinter &&) = delete;

        /*
         * destructor
         */
        virtual ~FlowPrinter()
        {}

        /*
         * this block takes no configuration parameters
         */
        virtual void _configure(const pugi::xml_node&  /*n*/ )
        {}

        /*
         * the main method
         * receives a Flow message and prints out its associated information
         * If the message belongs to another class, an exception is thrown.
         */
        virtual void _receive_msg(std::shared_ptr<const Msg>&& m, int /* index */)
        {
            if ( m->type() == MSG_ID(Flow) )
            {
                auto flow = static_cast<const Flow *>(m.get());
                std::stringstream ss;
                const FlowKey& fk = flow->key();
                int duration = flow->end_time() - flow->start_time();
                ss<<"packets="<<flow->packets() << ",";
                ss<<"bytes="<<flow->bytes() << ",";
                ss<<"start="<<flow->start_time() << ",";
                ss<<"end="<<flow->end_time() << ",";
                ss<<"duration.us="<<duration<< ",";
                ss<<"source.ip4="<<ip_to_string(fk.src_ip4)<< ",";
                ss<<"source.port="<<fk.src_port<< ",";
                ss<<"destination.ip4="<<ip_to_string(fk.dst_ip4)<< ",";
                ss<<"destination.port="<<fk.dst_port;
                /*
                ss<<"Flow of  "<< flow->packets() << " packets and "<<flow->bytes()<<" bytes begin at "<<flow->start_time()<<" end at "<<flow->end_time()<< "duration (ms.) "<<duration <<std::endl;
                ss<<"SRC IP "<<ip_to_string(fk.src_ip4)<<" SRC port "<<fk.src_port<<std::endl;
                ss<<"DST IP "<<ip_to_string(fk.dst_ip4)<<" DST port "<<fk.dst_port<<std::endl;
                //ss<<"protocol "<<fk.proto<<std::endl;
                */
                blocklog(ss.str(),log_info);

            }
                else
            {
                throw std::runtime_error("Flowprinter: wrong message type");
            }
        }

    private:

        int m_ingate_id;

    };

#ifndef _BLOCKMON_DOXYGEN_SKIP_
    REGISTER_BLOCK(FlowPrinter,"FlowPrinter");
#endif /* _BLOCKMON_DOXYGEN_SKIP_ */
}

<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Library General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * SPIPlugin.cpp
 * The SPI plugin for ola
 * Copyright (C) 2013 Simon Newton
 */

#include <memory>
#include <string>
#include <vector>
#include "ola/Logging.h"
#include "ola/StringUtils.h"
#include "ola/file/Util.h"
#include "ola/rdm/UID.h"
#include "ola/rdm/UIDAllocator.h"
#include "olad/PluginAdaptor.h"
#include "olad/Preferences.h"
#include "plugins/spi/SPIDevice.h"
#include "plugins/spi/SPIPlugin.h"

namespace ola {
namespace plugin {
namespace spi {

using ola::rdm::UID;
using std::auto_ptr;

const char SPIPlugin::DEFAULT_BASE_UID[] = "7a70:00000100";
const char SPIPlugin::DEFAULT_SPI_DEVICE_PREFIX[] = "spidev";
const char SPIPlugin::PLUGIN_NAME[] = "SPI";
const char SPIPlugin::PLUGIN_PREFIX[] = "spi";
const char SPIPlugin::SPI_BASE_UID_KEY[] = "base_uid";
const char SPIPlugin::SPI_DEVICE_PREFIX_KEY[] = "device_prefix";

/*
 * Start the plugin
 * For now we just have one device.
 */
bool SPIPlugin::StartHook() {
  const string uid_str = m_preferences->GetValue(SPI_BASE_UID_KEY);
  auto_ptr<UID> base_uid(UID::FromString(uid_str));
  if (!base_uid.get()) {
    OLA_WARN << "Invalid UID " << uid_str << ", defaulting to "
             << DEFAULT_BASE_UID;
    base_uid.reset(UID::FromString(DEFAULT_BASE_UID));
    if (!base_uid.get()) {
      OLA_WARN << "Invalid UID " << DEFAULT_BASE_UID;
      return false;
    }
  }

  vector<string> spi_files;
  vector<string> spi_prefixes = m_preferences->GetMultipleValue(
      SPI_DEVICE_PREFIX_KEY);
  ola::file::FindMatchingFiles("/dev", spi_prefixes, &spi_files);

  ola::rdm::UIDAllocator uid_allocator(*base_uid);
  vector<string>::const_iterator iter = spi_files.begin();
  for (; iter != spi_files.end(); ++iter) {
    SPIDevice *device = new SPIDevice(this, m_preferences, m_plugin_adaptor,
                                      *iter, &uid_allocator);

    if (!device)
      continue;

    if (!device->Start()) {
      delete device;
      continue;
    }
    m_devices.push_back(device);
    m_plugin_adaptor->RegisterDevice(device);
  }
  return true;
}

/*
 * Stop the plugin
 * @return true on success, false on failure
 */
bool SPIPlugin::StopHook() {
  vector<SPIDevice*>::iterator iter = m_devices.begin();
  bool ok = true;
  for (; iter != m_devices.end(); ++iter) {
    m_plugin_adaptor->UnregisterDevice(*iter);
    ok &= (*iter)->Stop();
    delete *iter;
  }
  return ok;
}

/*
 * Return the description for this plugin
 */
string SPIPlugin::Description() const {
  return
"SPI Plugin\n"
"----------------------------\n"
"\n"
"This plugin enables control of LED pixel strings using SPI. Each SPI output\n"
"is represented as an OLA Device. Devices can have multiple Ports, each of\n"
"which controls a pixel string. Each Port can use a different\n"
"personality (pixel type) and DMX start address, this allows a combination\n"
"of various strings lengths & pixel hardware types. The start address and\n"
"personality settings are controllable via RDM (each Port appears as a RDM\n"
"responder).\n"
"\n"
"To support multiple ports per SPI output, we use an SPI-Backend. Two\n"
"backends are supported right now, a software backend which concatenates\n"
"all the pixel data into a single buffer and a hardware multiplexer backend\n"
"which uses the GPIO pins to control an off-host multiplexer. It's\n"
"recommended to use the hardware multiplexer.\n"
"\n"
"--- Config file : ola-spi.conf ---\n"
"\n"
"base_uid = <string>\n"
"The starting UID to use for the SPI RDM , e.g. 7a70:00000100.\n"
"\n"
"device_prefix = <string>\n"
"The prefix of files to match in /dev. Usually set to 'spidev'. Each match\n"
"will instantiate a Device.\n"
"\n"
"--- Per Device Settings ---\n"
"<device>-spi-speed = <int>\n"
"The speed of the SPI bus, range is 0 - 32000000 Hz.\n"
"\n"
"<device>-ce-high = <int>\n"
"The mode of the CE pin. Set to false this pulls the CE pin low when writing\n"
"data. Set to true this will pull the pin high when writing.\n"
"\n"
"<device>-backend = [software | hardware]\n"
"The backend to use to multiplex the SPI data.\n"
"\n"
"<device>-gpio-pin = <int>\n"
"The GPIO pins to use for the hardware multiplexer. Add one line for each\n"
"pin. The number of ports will be 2 ** (# of pins).\n"
"\n"
"<device>-ports = <int>\n"
"If the software backend is used, this defines the number of ports which\n"
"will be created.\n"
"\n"
"<device>-sync-ports = <int>\n"
"Controls which port triggers a flush (write) of the SPI data. If set to -1\n"
"the SPI data is written when any port changes. This can result in a lot of\n"
"data writes (slow) and partial frames. If set to -2, the last port is used.\n"
"\n"
"--- Per Port Settings ---\n"
"Ports are indexed from 0.\n"
"\n"
"<device>-<port>-dmx-address = <int>\n"
"The DMX address to use. e.g. spidev0.1-0-dmx-address = 1\n"
"\n"
"<device>-<port>-personality = <int>\n"
"The RDM personality to use.\n"
"\n"
"<device>-<port>-pixel-count = <int>\n"
"The number of pixels for this port. e.g. spidev0.1-1-pixel-count = 20.\n"
"\n";
}

/*
 * Load the plugin prefs and default to sensible values
 */
bool SPIPlugin::SetDefaultPreferences() {
  bool save = false;

  if (!m_preferences)
    return false;

  save |= m_preferences->SetDefaultValue(SPI_DEVICE_PREFIX_KEY,
                                         StringValidator(),
                                         DEFAULT_SPI_DEVICE_PREFIX);
  save |= m_preferences->SetDefaultValue(SPI_BASE_UID_KEY,
                                         StringValidator(),
                                         DEFAULT_BASE_UID);
  if (save)
    m_preferences->Save();

  if (m_preferences->GetValue(SPI_DEVICE_PREFIX_KEY).empty())
    return false;

  return true;
}
}  // namespace spi
}  // namespace plugin
}  // namespace ola
<commit_msg>Correct the config help<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Library General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 * SPIPlugin.cpp
 * The SPI plugin for ola
 * Copyright (C) 2013 Simon Newton
 */

#include <memory>
#include <string>
#include <vector>
#include "ola/Logging.h"
#include "ola/StringUtils.h"
#include "ola/file/Util.h"
#include "ola/rdm/UID.h"
#include "ola/rdm/UIDAllocator.h"
#include "olad/PluginAdaptor.h"
#include "olad/Preferences.h"
#include "plugins/spi/SPIDevice.h"
#include "plugins/spi/SPIPlugin.h"

namespace ola {
namespace plugin {
namespace spi {

using ola::rdm::UID;
using std::auto_ptr;

const char SPIPlugin::DEFAULT_BASE_UID[] = "7a70:00000100";
const char SPIPlugin::DEFAULT_SPI_DEVICE_PREFIX[] = "spidev";
const char SPIPlugin::PLUGIN_NAME[] = "SPI";
const char SPIPlugin::PLUGIN_PREFIX[] = "spi";
const char SPIPlugin::SPI_BASE_UID_KEY[] = "base_uid";
const char SPIPlugin::SPI_DEVICE_PREFIX_KEY[] = "device_prefix";

/*
 * Start the plugin
 * For now we just have one device.
 */
bool SPIPlugin::StartHook() {
  const string uid_str = m_preferences->GetValue(SPI_BASE_UID_KEY);
  auto_ptr<UID> base_uid(UID::FromString(uid_str));
  if (!base_uid.get()) {
    OLA_WARN << "Invalid UID " << uid_str << ", defaulting to "
             << DEFAULT_BASE_UID;
    base_uid.reset(UID::FromString(DEFAULT_BASE_UID));
    if (!base_uid.get()) {
      OLA_WARN << "Invalid UID " << DEFAULT_BASE_UID;
      return false;
    }
  }

  vector<string> spi_files;
  vector<string> spi_prefixes = m_preferences->GetMultipleValue(
      SPI_DEVICE_PREFIX_KEY);
  ola::file::FindMatchingFiles("/dev", spi_prefixes, &spi_files);

  ola::rdm::UIDAllocator uid_allocator(*base_uid);
  vector<string>::const_iterator iter = spi_files.begin();
  for (; iter != spi_files.end(); ++iter) {
    SPIDevice *device = new SPIDevice(this, m_preferences, m_plugin_adaptor,
                                      *iter, &uid_allocator);

    if (!device)
      continue;

    if (!device->Start()) {
      delete device;
      continue;
    }
    m_devices.push_back(device);
    m_plugin_adaptor->RegisterDevice(device);
  }
  return true;
}

/*
 * Stop the plugin
 * @return true on success, false on failure
 */
bool SPIPlugin::StopHook() {
  vector<SPIDevice*>::iterator iter = m_devices.begin();
  bool ok = true;
  for (; iter != m_devices.end(); ++iter) {
    m_plugin_adaptor->UnregisterDevice(*iter);
    ok &= (*iter)->Stop();
    delete *iter;
  }
  return ok;
}

/*
 * Return the description for this plugin
 */
string SPIPlugin::Description() const {
  return
"SPI Plugin\n"
"----------------------------\n"
"\n"
"This plugin enables control of LED pixel strings using SPI. Each SPI output\n"
"is represented as an OLA Device. Devices can have multiple Ports, each of\n"
"which controls a pixel string. Each Port can use a different\n"
"personality (pixel type) and DMX start address, this allows a combination\n"
"of various strings lengths & pixel hardware types. The start address and\n"
"personality settings are controllable via RDM (each Port appears as a RDM\n"
"responder).\n"
"\n"
"To support multiple ports per SPI output, we use an SPI-Backend. Two\n"
"backends are supported right now, a software backend which concatenates\n"
"all the pixel data into a single buffer and a hardware multiplexer backend\n"
"which uses the GPIO pins to control an off-host multiplexer. It's\n"
"recommended to use the hardware multiplexer.\n"
"\n"
"--- Config file : ola-spi.conf ---\n"
"\n"
"base_uid = <string>\n"
"The starting UID to use for the SPI RDM , e.g. 7a70:00000100.\n"
"\n"
"device_prefix = <string>\n"
"The prefix of files to match in /dev. Usually set to 'spidev'. Each match\n"
"will instantiate a Device.\n"
"\n"
"--- Per Device Settings ---\n"
"<device>-spi-speed = <int>\n"
"The speed of the SPI bus, range is 0 - 32000000 Hz.\n"
"\n"
"<device>-ce-high = <bool>\n"
"The mode of the CE pin. Set to false this pulls the CE pin low when writing\n"
"data. Set to true this will pull the pin high when writing.\n"
"\n"
"<device>-backend = [software | hardware]\n"
"The backend to use to multiplex the SPI data.\n"
"\n"
"<device>-gpio-pin = <int>\n"
"The GPIO pins to use for the hardware multiplexer. Add one line for each\n"
"pin. The number of ports will be 2 ** (# of pins).\n"
"\n"
"<device>-ports = <int>\n"
"If the software backend is used, this defines the number of ports which\n"
"will be created.\n"
"\n"
"<device>-sync-ports = <int>\n"
"Controls which port triggers a flush (write) of the SPI data. If set to -1\n"
"the SPI data is written when any port changes. This can result in a lot of\n"
"data writes (slow) and partial frames. If set to -2, the last port is used.\n"
"\n"
"--- Per Port Settings ---\n"
"Ports are indexed from 0.\n"
"\n"
"<device>-<port>-dmx-address = <int>\n"
"The DMX address to use. e.g. spidev0.1-0-dmx-address = 1\n"
"\n"
"<device>-<port>-personality = <int>\n"
"The RDM personality to use.\n"
"\n"
"<device>-<port>-pixel-count = <int>\n"
"The number of pixels for this port. e.g. spidev0.1-1-pixel-count = 20.\n"
"\n";
}

/*
 * Load the plugin prefs and default to sensible values
 */
bool SPIPlugin::SetDefaultPreferences() {
  bool save = false;

  if (!m_preferences)
    return false;

  save |= m_preferences->SetDefaultValue(SPI_DEVICE_PREFIX_KEY,
                                         StringValidator(),
                                         DEFAULT_SPI_DEVICE_PREFIX);
  save |= m_preferences->SetDefaultValue(SPI_BASE_UID_KEY,
                                         StringValidator(),
                                         DEFAULT_BASE_UID);
  if (save)
    m_preferences->Save();

  if (m_preferences->GetValue(SPI_DEVICE_PREFIX_KEY).empty())
    return false;

  return true;
}
}  // namespace spi
}  // namespace plugin
}  // namespace ola
<|endoftext|>


<commit_before>//===- CallGraphSCCPass.cpp - Pass that operates BU on call graph ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the CallGraphSCCPass class, which is used for passes
// which are implemented as bottom-up traversals on the call graph.  Because
// there may be cycles in the call graph, passes of this type operate on the
// call-graph in SCC order: that is, they process function bottom-up, except for
// recursive functions, which they process all at once.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "cgscc-passmgr"
#include "llvm/CallGraphSCCPass.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/ADT/SCCIterator.h"
#include "llvm/PassManagers.h"
#include "llvm/Function.h"
#include "llvm/Support/Debug.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

//===----------------------------------------------------------------------===//
// CGPassManager
//
/// CGPassManager manages FPPassManagers and CalLGraphSCCPasses.

namespace {

class CGPassManager : public ModulePass, public PMDataManager {
public:
  static char ID;
  explicit CGPassManager(int Depth)
    : ModulePass(&ID), PMDataManager(Depth) { }

  /// run - Execute all of the passes scheduled for execution.  Keep track of
  /// whether any of the passes modifies the module, and if so, return true.
  bool runOnModule(Module &M);

  bool doInitialization(CallGraph &CG);
  bool doFinalization(CallGraph &CG);

  /// Pass Manager itself does not invalidate any analysis info.
  void getAnalysisUsage(AnalysisUsage &Info) const {
    // CGPassManager walks SCC and it needs CallGraph.
    Info.addRequired<CallGraph>();
    Info.setPreservesAll();
  }

  virtual const char *getPassName() const {
    return "CallGraph Pass Manager";
  }

  // Print passes managed by this manager
  void dumpPassStructure(unsigned Offset) {
    errs().indent(Offset*2) << "Call Graph SCC Pass Manager\n";
    for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
      Pass *P = getContainedPass(Index);
      P->dumpPassStructure(Offset + 1);
      dumpLastUses(P, Offset+1);
    }
  }

  Pass *getContainedPass(unsigned N) {
    assert(N < PassVector.size() && "Pass number out of range!");
    return static_cast<Pass *>(PassVector[N]);
  }

  virtual PassManagerType getPassManagerType() const {
    return PMT_CallGraphPassManager;
  }

private:
  bool RunPassOnSCC(Pass *P, std::vector<CallGraphNode*> &CurSCC,
                    CallGraph &CG, bool &CallGraphUpToDate);
  void RefreshCallGraph(std::vector<CallGraphNode*> &CurSCC, CallGraph &CG,
                        bool IsCheckingMode);
};

} // end anonymous namespace.

char CGPassManager::ID = 0;

bool CGPassManager::RunPassOnSCC(Pass *P, std::vector<CallGraphNode*> &CurSCC,
                                 CallGraph &CG, bool &CallGraphUpToDate) {
  bool Changed = false;
  if (CallGraphSCCPass *CGSP = dynamic_cast<CallGraphSCCPass*>(P)) {
    if (!CallGraphUpToDate) {
      RefreshCallGraph(CurSCC, CG, false);
      CallGraphUpToDate = true;
    }

    StartPassTimer(CGSP);
    Changed = CGSP->runOnSCC(CurSCC);
    StopPassTimer(CGSP);

    // After the CGSCCPass is done, when assertions are enabled, use
    // RefreshCallGraph to verify that the callgraph was correctly updated.
#ifndef NDEBUG
    if (Changed)
      RefreshCallGraph(CurSCC, CG, true);
#endif

    return Changed;
  }

  StartPassTimer(P);
  FPPassManager *FPP = dynamic_cast<FPPassManager *>(P);
  assert(FPP && "Invalid CGPassManager member");

  // Run pass P on all functions in the current SCC.
  for (unsigned i = 0, e = CurSCC.size(); i != e; ++i) {
    if (Function *F = CurSCC[i]->getFunction()) {
      dumpPassInfo(P, EXECUTION_MSG, ON_FUNCTION_MSG, F->getName());
      Changed |= FPP->runOnFunction(*F);
    }
  }
  StopPassTimer(P);

  // The function pass(es) modified the IR, they may have clobbered the
  // callgraph.
  if (Changed && CallGraphUpToDate) {
    DEBUG(errs() << "CGSCCPASSMGR: Pass Dirtied SCC: "
                 << P->getPassName() << '\n');
    CallGraphUpToDate = false;
  }
  return Changed;
}

/// RefreshCallGraph - Scan the functions in the specified CFG and resync the
/// callgraph with the call sites found in it.  This is used after
/// FunctionPasses have potentially munged the callgraph, and can be used after
/// CallGraphSCC passes to verify that they correctly updated the callgraph.
///
void CGPassManager::RefreshCallGraph(std::vector<CallGraphNode*> &CurSCC,
                                     CallGraph &CG, bool CheckingMode) {
  DenseMap<Value*, CallGraphNode*> CallSites;

  DEBUG(errs() << "CGSCCPASSMGR: Refreshing SCC with " << CurSCC.size()
               << " nodes:\n";
        for (unsigned i = 0, e = CurSCC.size(); i != e; ++i)
          CurSCC[i]->dump();
        );

  bool MadeChange = false;

  // Scan all functions in the SCC.
  for (unsigned sccidx = 0, e = CurSCC.size(); sccidx != e; ++sccidx) {
    CallGraphNode *CGN = CurSCC[sccidx];
    Function *F = CGN->getFunction();
    if (F == 0 || F->isDeclaration()) continue;

    // Walk the function body looking for call sites.  Sync up the call sites in
    // CGN with those actually in the function.

    // Get the set of call sites currently in the function.
    for (CallGraphNode::iterator I = CGN->begin(), E = CGN->end(); I != E; ) {
      // If this call site is null, then the function pass deleted the call
      // entirely and the WeakVH nulled it out.
      if (I->first == 0 ||
          // If we've already seen this call site, then the FunctionPass RAUW'd
          // one call with another, which resulted in two "uses" in the edge
          // list of the same call.
          CallSites.count(I->first) ||

          // If the call edge is not from a call or invoke, then the function
          // pass RAUW'd a call with another value.  This can happen when
          // constant folding happens of well known functions etc.
          CallSite::get(I->first).getInstruction() == 0) {
        assert(!CheckingMode &&
               "CallGraphSCCPass did not update the CallGraph correctly!");

        // Just remove the edge from the set of callees.
        bool wasLast = I + 1 == E;
        CGN->removeCallEdge(I);
        if (wasLast)
          // I is now a singular iterator, do not compare with E.
          break;
        E = CGN->end();
        continue;
      }

      assert(!CallSites.count(I->first) &&
             "Call site occurs in node multiple times");
      CallSites.insert(std::make_pair(I->first, I->second));
      ++I;
    }

    // Loop over all of the instructions in the function, getting the callsites.
    for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
      for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
        CallSite CS = CallSite::get(I);
        if (!CS.getInstruction() || isa<DbgInfoIntrinsic>(I)) continue;

        // If this call site already existed in the callgraph, just verify it
        // matches up to expectations and remove it from CallSites.
        DenseMap<Value*, CallGraphNode*>::iterator ExistingIt =
          CallSites.find(CS.getInstruction());
        if (ExistingIt != CallSites.end()) {
          CallGraphNode *ExistingNode = ExistingIt->second;

          // Remove from CallSites since we have now seen it.
          CallSites.erase(ExistingIt);

          // Verify that the callee is right.
          if (ExistingNode->getFunction() == CS.getCalledFunction())
            continue;

          // If we are in checking mode, we are not allowed to actually mutate
          // the callgraph.  If this is a case where we can infer that the
          // callgraph is less precise than it could be (e.g. an indirect call
          // site could be turned direct), don't reject it in checking mode, and
          // don't tweak it to be more precise.
          if (CheckingMode && CS.getCalledFunction() &&
              ExistingNode->getFunction() == 0)
            continue;

          assert(!CheckingMode &&
                 "CallGraphSCCPass did not update the CallGraph correctly!");

          // If not, we either went from a direct call to indirect, indirect to
          // direct, or direct to different direct.
          CallGraphNode *CalleeNode;
          if (Function *Callee = CS.getCalledFunction())
            CalleeNode = CG.getOrInsertFunction(Callee);
          else
            CalleeNode = CG.getCallsExternalNode();

          // Update the edge target in CGN.
          for (CallGraphNode::iterator I = CGN->begin(); ; ++I) {
            assert(I != CGN->end() && "Didn't find call entry");
            if (I->first == CS.getInstruction()) {
              I->second = CalleeNode;
              break;
            }
          }
          MadeChange = true;
          continue;
        }

        assert(!CheckingMode &&
               "CallGraphSCCPass did not update the CallGraph correctly!");

        // If the call site didn't exist in the CGN yet, add it.  We assume that
        // newly introduced call sites won't be indirect.  This could be fixed
        // in the future.
        CallGraphNode *CalleeNode;
        if (Function *Callee = CS.getCalledFunction())
          CalleeNode = CG.getOrInsertFunction(Callee);
        else
          CalleeNode = CG.getCallsExternalNode();

        CGN->addCalledFunction(CS, CalleeNode);
        MadeChange = true;
      }

    // After scanning this function, if we still have entries in callsites, then
    // they are dangling pointers.  WeakVH should save us for this, so abort if
    // this happens.
    assert(CallSites.empty() && "Dangling pointers found in call sites map");

    // Periodically do an explicit clear to remove tombstones when processing
    // large scc's.
    if ((sccidx & 15) == 0)
      CallSites.clear();
  }

  DEBUG(if (MadeChange) {
          errs() << "CGSCCPASSMGR: Refreshed SCC is now:\n";
          for (unsigned i = 0, e = CurSCC.size(); i != e; ++i)
            CurSCC[i]->dump();
         } else {
           errs() << "CGSCCPASSMGR: SCC Refresh didn't change call graph.\n";
         }
        );
}

/// run - Execute all of the passes scheduled for execution.  Keep track of
/// whether any of the passes modifies the module, and if so, return true.
bool CGPassManager::runOnModule(Module &M) {
  CallGraph &CG = getAnalysis<CallGraph>();
  bool Changed = doInitialization(CG);

  std::vector<CallGraphNode*> CurSCC;

  // Walk the callgraph in bottom-up SCC order.
  for (scc_iterator<CallGraph*> CGI = scc_begin(&CG), E = scc_end(&CG);
       CGI != E;) {
    // Copy the current SCC and increment past it so that the pass can hack
    // on the SCC if it wants to without invalidating our iterator.
    CurSCC = *CGI;
    ++CGI;

    // CallGraphUpToDate - Keep track of whether the callgraph is known to be
    // up-to-date or not.  The CGSSC pass manager runs two types of passes:
    // CallGraphSCC Passes and other random function passes.  Because other
    // random function passes are not CallGraph aware, they may clobber the
    // call graph by introducing new calls or deleting other ones.  This flag
    // is set to false when we run a function pass so that we know to clean up
    // the callgraph when we need to run a CGSCCPass again.
    bool CallGraphUpToDate = true;

    // Run all passes on current SCC.
    for (unsigned PassNo = 0, e = getNumContainedPasses();
         PassNo != e; ++PassNo) {
      Pass *P = getContainedPass(PassNo);

      dumpPassInfo(P, EXECUTION_MSG, ON_CG_MSG, "");
      dumpRequiredSet(P);

      initializeAnalysisImpl(P);

      // Actually run this pass on the current SCC.
      Changed |= RunPassOnSCC(P, CurSCC, CG, CallGraphUpToDate);

      if (Changed)
        dumpPassInfo(P, MODIFICATION_MSG, ON_CG_MSG, "");
      dumpPreservedSet(P);

      verifyPreservedAnalysis(P);
      removeNotPreservedAnalysis(P);
      recordAvailableAnalysis(P);
      removeDeadPasses(P, "", ON_CG_MSG);
    }

    // If the callgraph was left out of date (because the last pass run was a
    // functionpass), refresh it before we move on to the next SCC.
    if (!CallGraphUpToDate)
      RefreshCallGraph(CurSCC, CG, false);
  }
  Changed |= doFinalization(CG);
  return Changed;
}

/// Initialize CG
bool CGPassManager::doInitialization(CallGraph &CG) {
  bool Changed = false;
  for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
    Pass *P = getContainedPass(Index);
    if (CallGraphSCCPass *CGSP = dynamic_cast<CallGraphSCCPass *>(P)) {
      Changed |= CGSP->doInitialization(CG);
    } else {
      FPPassManager *FP = dynamic_cast<FPPassManager *>(P);
      assert (FP && "Invalid CGPassManager member");
      Changed |= FP->doInitialization(CG.getModule());
    }
  }
  return Changed;
}

/// Finalize CG
bool CGPassManager::doFinalization(CallGraph &CG) {
  bool Changed = false;
  for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
    Pass *P = getContainedPass(Index);
    if (CallGraphSCCPass *CGSP = dynamic_cast<CallGraphSCCPass *>(P)) {
      Changed |= CGSP->doFinalization(CG);
    } else {
      FPPassManager *FP = dynamic_cast<FPPassManager *>(P);
      assert (FP && "Invalid CGPassManager member");
      Changed |= FP->doFinalization(CG.getModule());
    }
  }
  return Changed;
}

/// Assign pass manager to manage this pass.
void CallGraphSCCPass::assignPassManager(PMStack &PMS,
                                         PassManagerType PreferredType) {
  // Find CGPassManager
  while (!PMS.empty() &&
         PMS.top()->getPassManagerType() > PMT_CallGraphPassManager)
    PMS.pop();

  assert (!PMS.empty() && "Unable to handle Call Graph Pass");
  CGPassManager *CGP = dynamic_cast<CGPassManager *>(PMS.top());

  // Create new Call Graph SCC Pass Manager if it does not exist.
  if (!CGP) {

    assert (!PMS.empty() && "Unable to create Call Graph Pass Manager");
    PMDataManager *PMD = PMS.top();

    // [1] Create new Call Graph Pass Manager
    CGP = new CGPassManager(PMD->getDepth() + 1);

    // [2] Set up new manager's top level manager
    PMTopLevelManager *TPM = PMD->getTopLevelManager();
    TPM->addIndirectPassManager(CGP);

    // [3] Assign manager to manage this new manager. This may create
    // and push new managers into PMS
    Pass *P = dynamic_cast<Pass *>(CGP);
    TPM->schedulePass(P);

    // [4] Push new manager into PMS
    PMS.push(CGP);
  }

  CGP->add(this);
}

/// getAnalysisUsage - For this class, we declare that we require and preserve
/// the call graph.  If the derived class implements this method, it should
/// always explicitly call the implementation here.
void CallGraphSCCPass::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<CallGraph>();
  AU.addPreserved<CallGraph>();
}
<commit_msg>one more try at making this simpler, hopefully it won't break everything :)<commit_after>//===- CallGraphSCCPass.cpp - Pass that operates BU on call graph ---------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the CallGraphSCCPass class, which is used for passes
// which are implemented as bottom-up traversals on the call graph.  Because
// there may be cycles in the call graph, passes of this type operate on the
// call-graph in SCC order: that is, they process function bottom-up, except for
// recursive functions, which they process all at once.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "cgscc-passmgr"
#include "llvm/CallGraphSCCPass.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/ADT/SCCIterator.h"
#include "llvm/PassManagers.h"
#include "llvm/Function.h"
#include "llvm/Support/Debug.h"
#include "llvm/IntrinsicInst.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

//===----------------------------------------------------------------------===//
// CGPassManager
//
/// CGPassManager manages FPPassManagers and CalLGraphSCCPasses.

namespace {

class CGPassManager : public ModulePass, public PMDataManager {
public:
  static char ID;
  explicit CGPassManager(int Depth)
    : ModulePass(&ID), PMDataManager(Depth) { }

  /// run - Execute all of the passes scheduled for execution.  Keep track of
  /// whether any of the passes modifies the module, and if so, return true.
  bool runOnModule(Module &M);

  bool doInitialization(CallGraph &CG);
  bool doFinalization(CallGraph &CG);

  /// Pass Manager itself does not invalidate any analysis info.
  void getAnalysisUsage(AnalysisUsage &Info) const {
    // CGPassManager walks SCC and it needs CallGraph.
    Info.addRequired<CallGraph>();
    Info.setPreservesAll();
  }

  virtual const char *getPassName() const {
    return "CallGraph Pass Manager";
  }

  // Print passes managed by this manager
  void dumpPassStructure(unsigned Offset) {
    errs().indent(Offset*2) << "Call Graph SCC Pass Manager\n";
    for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
      Pass *P = getContainedPass(Index);
      P->dumpPassStructure(Offset + 1);
      dumpLastUses(P, Offset+1);
    }
  }

  Pass *getContainedPass(unsigned N) {
    assert(N < PassVector.size() && "Pass number out of range!");
    return static_cast<Pass *>(PassVector[N]);
  }

  virtual PassManagerType getPassManagerType() const {
    return PMT_CallGraphPassManager;
  }

private:
  bool RunPassOnSCC(Pass *P, std::vector<CallGraphNode*> &CurSCC,
                    CallGraph &CG, bool &CallGraphUpToDate);
  void RefreshCallGraph(std::vector<CallGraphNode*> &CurSCC, CallGraph &CG,
                        bool IsCheckingMode);
};

} // end anonymous namespace.

char CGPassManager::ID = 0;

bool CGPassManager::RunPassOnSCC(Pass *P, std::vector<CallGraphNode*> &CurSCC,
                                 CallGraph &CG, bool &CallGraphUpToDate) {
  bool Changed = false;
  if (CallGraphSCCPass *CGSP = dynamic_cast<CallGraphSCCPass*>(P)) {
    if (!CallGraphUpToDate) {
      RefreshCallGraph(CurSCC, CG, false);
      CallGraphUpToDate = true;
    }

    StartPassTimer(CGSP);
    Changed = CGSP->runOnSCC(CurSCC);
    StopPassTimer(CGSP);

    // After the CGSCCPass is done, when assertions are enabled, use
    // RefreshCallGraph to verify that the callgraph was correctly updated.
#ifndef NDEBUG
    if (Changed)
      RefreshCallGraph(CurSCC, CG, true);
#endif

    return Changed;
  }

  StartPassTimer(P);
  FPPassManager *FPP = dynamic_cast<FPPassManager *>(P);
  assert(FPP && "Invalid CGPassManager member");

  // Run pass P on all functions in the current SCC.
  for (unsigned i = 0, e = CurSCC.size(); i != e; ++i) {
    if (Function *F = CurSCC[i]->getFunction()) {
      dumpPassInfo(P, EXECUTION_MSG, ON_FUNCTION_MSG, F->getName());
      Changed |= FPP->runOnFunction(*F);
    }
  }
  StopPassTimer(P);

  // The function pass(es) modified the IR, they may have clobbered the
  // callgraph.
  if (Changed && CallGraphUpToDate) {
    DEBUG(errs() << "CGSCCPASSMGR: Pass Dirtied SCC: "
                 << P->getPassName() << '\n');
    CallGraphUpToDate = false;
  }
  return Changed;
}

/// RefreshCallGraph - Scan the functions in the specified CFG and resync the
/// callgraph with the call sites found in it.  This is used after
/// FunctionPasses have potentially munged the callgraph, and can be used after
/// CallGraphSCC passes to verify that they correctly updated the callgraph.
///
void CGPassManager::RefreshCallGraph(std::vector<CallGraphNode*> &CurSCC,
                                     CallGraph &CG, bool CheckingMode) {
  DenseMap<Value*, CallGraphNode*> CallSites;

  DEBUG(errs() << "CGSCCPASSMGR: Refreshing SCC with " << CurSCC.size()
               << " nodes:\n";
        for (unsigned i = 0, e = CurSCC.size(); i != e; ++i)
          CurSCC[i]->dump();
        );

  bool MadeChange = false;

  // Scan all functions in the SCC.
  for (unsigned sccidx = 0, e = CurSCC.size(); sccidx != e; ++sccidx) {
    CallGraphNode *CGN = CurSCC[sccidx];
    Function *F = CGN->getFunction();
    if (F == 0 || F->isDeclaration()) continue;

    // Walk the function body looking for call sites.  Sync up the call sites in
    // CGN with those actually in the function.

    // Get the set of call sites currently in the function.
    for (CallGraphNode::iterator I = CGN->begin(), E = CGN->end(); I != E; ) {
      // If this call site is null, then the function pass deleted the call
      // entirely and the WeakVH nulled it out.
      if (I->first == 0 ||
          // If we've already seen this call site, then the FunctionPass RAUW'd
          // one call with another, which resulted in two "uses" in the edge
          // list of the same call.
          CallSites.count(I->first) ||

          // If the call edge is not from a call or invoke, then the function
          // pass RAUW'd a call with another value.  This can happen when
          // constant folding happens of well known functions etc.
          CallSite::get(I->first).getInstruction() == 0) {
        assert(!CheckingMode &&
               "CallGraphSCCPass did not update the CallGraph correctly!");

        // Just remove the edge from the set of callees.
        CGN->removeCallEdge(I);

        // If we removed the last edge, get out of the loop.
        if (CGN->empty()) break;

        E = CGN->end();
        continue;
      }

      assert(!CallSites.count(I->first) &&
             "Call site occurs in node multiple times");
      CallSites.insert(std::make_pair(I->first, I->second));
      ++I;
    }

    // Loop over all of the instructions in the function, getting the callsites.
    for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB)
      for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
        CallSite CS = CallSite::get(I);
        if (!CS.getInstruction() || isa<DbgInfoIntrinsic>(I)) continue;

        // If this call site already existed in the callgraph, just verify it
        // matches up to expectations and remove it from CallSites.
        DenseMap<Value*, CallGraphNode*>::iterator ExistingIt =
          CallSites.find(CS.getInstruction());
        if (ExistingIt != CallSites.end()) {
          CallGraphNode *ExistingNode = ExistingIt->second;

          // Remove from CallSites since we have now seen it.
          CallSites.erase(ExistingIt);

          // Verify that the callee is right.
          if (ExistingNode->getFunction() == CS.getCalledFunction())
            continue;

          // If we are in checking mode, we are not allowed to actually mutate
          // the callgraph.  If this is a case where we can infer that the
          // callgraph is less precise than it could be (e.g. an indirect call
          // site could be turned direct), don't reject it in checking mode, and
          // don't tweak it to be more precise.
          if (CheckingMode && CS.getCalledFunction() &&
              ExistingNode->getFunction() == 0)
            continue;

          assert(!CheckingMode &&
                 "CallGraphSCCPass did not update the CallGraph correctly!");

          // If not, we either went from a direct call to indirect, indirect to
          // direct, or direct to different direct.
          CallGraphNode *CalleeNode;
          if (Function *Callee = CS.getCalledFunction())
            CalleeNode = CG.getOrInsertFunction(Callee);
          else
            CalleeNode = CG.getCallsExternalNode();

          // Update the edge target in CGN.
          for (CallGraphNode::iterator I = CGN->begin(); ; ++I) {
            assert(I != CGN->end() && "Didn't find call entry");
            if (I->first == CS.getInstruction()) {
              I->second = CalleeNode;
              break;
            }
          }
          MadeChange = true;
          continue;
        }

        assert(!CheckingMode &&
               "CallGraphSCCPass did not update the CallGraph correctly!");

        // If the call site didn't exist in the CGN yet, add it.  We assume that
        // newly introduced call sites won't be indirect.  This could be fixed
        // in the future.
        CallGraphNode *CalleeNode;
        if (Function *Callee = CS.getCalledFunction())
          CalleeNode = CG.getOrInsertFunction(Callee);
        else
          CalleeNode = CG.getCallsExternalNode();

        CGN->addCalledFunction(CS, CalleeNode);
        MadeChange = true;
      }

    // After scanning this function, if we still have entries in callsites, then
    // they are dangling pointers.  WeakVH should save us for this, so abort if
    // this happens.
    assert(CallSites.empty() && "Dangling pointers found in call sites map");

    // Periodically do an explicit clear to remove tombstones when processing
    // large scc's.
    if ((sccidx & 15) == 0)
      CallSites.clear();
  }

  DEBUG(if (MadeChange) {
          errs() << "CGSCCPASSMGR: Refreshed SCC is now:\n";
          for (unsigned i = 0, e = CurSCC.size(); i != e; ++i)
            CurSCC[i]->dump();
         } else {
           errs() << "CGSCCPASSMGR: SCC Refresh didn't change call graph.\n";
         }
        );
}

/// run - Execute all of the passes scheduled for execution.  Keep track of
/// whether any of the passes modifies the module, and if so, return true.
bool CGPassManager::runOnModule(Module &M) {
  CallGraph &CG = getAnalysis<CallGraph>();
  bool Changed = doInitialization(CG);

  std::vector<CallGraphNode*> CurSCC;

  // Walk the callgraph in bottom-up SCC order.
  for (scc_iterator<CallGraph*> CGI = scc_begin(&CG), E = scc_end(&CG);
       CGI != E;) {
    // Copy the current SCC and increment past it so that the pass can hack
    // on the SCC if it wants to without invalidating our iterator.
    CurSCC = *CGI;
    ++CGI;

    // CallGraphUpToDate - Keep track of whether the callgraph is known to be
    // up-to-date or not.  The CGSSC pass manager runs two types of passes:
    // CallGraphSCC Passes and other random function passes.  Because other
    // random function passes are not CallGraph aware, they may clobber the
    // call graph by introducing new calls or deleting other ones.  This flag
    // is set to false when we run a function pass so that we know to clean up
    // the callgraph when we need to run a CGSCCPass again.
    bool CallGraphUpToDate = true;

    // Run all passes on current SCC.
    for (unsigned PassNo = 0, e = getNumContainedPasses();
         PassNo != e; ++PassNo) {
      Pass *P = getContainedPass(PassNo);

      dumpPassInfo(P, EXECUTION_MSG, ON_CG_MSG, "");
      dumpRequiredSet(P);

      initializeAnalysisImpl(P);

      // Actually run this pass on the current SCC.
      Changed |= RunPassOnSCC(P, CurSCC, CG, CallGraphUpToDate);

      if (Changed)
        dumpPassInfo(P, MODIFICATION_MSG, ON_CG_MSG, "");
      dumpPreservedSet(P);

      verifyPreservedAnalysis(P);
      removeNotPreservedAnalysis(P);
      recordAvailableAnalysis(P);
      removeDeadPasses(P, "", ON_CG_MSG);
    }

    // If the callgraph was left out of date (because the last pass run was a
    // functionpass), refresh it before we move on to the next SCC.
    if (!CallGraphUpToDate)
      RefreshCallGraph(CurSCC, CG, false);
  }
  Changed |= doFinalization(CG);
  return Changed;
}

/// Initialize CG
bool CGPassManager::doInitialization(CallGraph &CG) {
  bool Changed = false;
  for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
    Pass *P = getContainedPass(Index);
    if (CallGraphSCCPass *CGSP = dynamic_cast<CallGraphSCCPass *>(P)) {
      Changed |= CGSP->doInitialization(CG);
    } else {
      FPPassManager *FP = dynamic_cast<FPPassManager *>(P);
      assert (FP && "Invalid CGPassManager member");
      Changed |= FP->doInitialization(CG.getModule());
    }
  }
  return Changed;
}

/// Finalize CG
bool CGPassManager::doFinalization(CallGraph &CG) {
  bool Changed = false;
  for (unsigned Index = 0; Index < getNumContainedPasses(); ++Index) {
    Pass *P = getContainedPass(Index);
    if (CallGraphSCCPass *CGSP = dynamic_cast<CallGraphSCCPass *>(P)) {
      Changed |= CGSP->doFinalization(CG);
    } else {
      FPPassManager *FP = dynamic_cast<FPPassManager *>(P);
      assert (FP && "Invalid CGPassManager member");
      Changed |= FP->doFinalization(CG.getModule());
    }
  }
  return Changed;
}

/// Assign pass manager to manage this pass.
void CallGraphSCCPass::assignPassManager(PMStack &PMS,
                                         PassManagerType PreferredType) {
  // Find CGPassManager
  while (!PMS.empty() &&
         PMS.top()->getPassManagerType() > PMT_CallGraphPassManager)
    PMS.pop();

  assert (!PMS.empty() && "Unable to handle Call Graph Pass");
  CGPassManager *CGP = dynamic_cast<CGPassManager *>(PMS.top());

  // Create new Call Graph SCC Pass Manager if it does not exist.
  if (!CGP) {

    assert (!PMS.empty() && "Unable to create Call Graph Pass Manager");
    PMDataManager *PMD = PMS.top();

    // [1] Create new Call Graph Pass Manager
    CGP = new CGPassManager(PMD->getDepth() + 1);

    // [2] Set up new manager's top level manager
    PMTopLevelManager *TPM = PMD->getTopLevelManager();
    TPM->addIndirectPassManager(CGP);

    // [3] Assign manager to manage this new manager. This may create
    // and push new managers into PMS
    Pass *P = dynamic_cast<Pass *>(CGP);
    TPM->schedulePass(P);

    // [4] Push new manager into PMS
    PMS.push(CGP);
  }

  CGP->add(this);
}

/// getAnalysisUsage - For this class, we declare that we require and preserve
/// the call graph.  If the derived class implements this method, it should
/// always explicitly call the implementation here.
void CallGraphSCCPass::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<CallGraph>();
  AU.addPreserved<CallGraph>();
}
<|endoftext|>