<commit_before>/*
 * Copyright 2007-2019 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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
 * FOUNDATION 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 "nghttp2/Server.hxx"
#include "http/Headers.hxx"
#include "http/IncomingRequest.hxx"
#include "http_server/Handler.hxx"
#include "event/Loop.hxx"
#include "event/net/TemplateServerSocket.hxx"
#include "net/UniqueSocketDescriptor.hxx"
#include "util/PrintException.hxx"
#include "pool/RootPool.hxx"
#include "fb_pool.hxx"

class Connection final
    : public boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>,
      HttpServerConnectionHandler
{
    NgHttp2::ServerConnection http;

public:
    Connection(struct pool &pool, EventLoop &event_loop,
               UniqueSocketDescriptor fd, SocketAddress address)
        :http(pool, event_loop, std::move(fd), FD_TCP, nullptr,
              address,
              *this) {}

    /* virtual methods from class HttpServerConnectionHandler */
    void HandleHttpRequest(IncomingHttpRequest &request,
                           const StopwatchPtr &,
                           CancellablePointer &cancel_ptr) noexcept override {
        (void)cancel_ptr;
        // TODO

        if (request.body)
            request.SendResponse(HTTP_STATUS_OK, {},
                                 std::move(request.body));
        else
            request.SendMessage(HTTP_STATUS_OK, "Hello, world!\n");
    }

    void LogHttpRequest(IncomingHttpRequest &,
                        http_status_t, off_t,
                        uint64_t,
                        uint64_t) noexcept override {}

    void HttpConnectionError(std::exception_ptr e) noexcept override {
        PrintException(e);
        delete this;
    }

    void HttpConnectionClosed() noexcept override {
        delete this;
    }
};

typedef TemplateServerSocket<Connection, struct pool &,
                             EventLoop &> Listener;

int
main(int, char **) noexcept
try {
    const ScopeFbPoolInit fb_pool_init;
    RootPool pool;
    EventLoop event_loop;

    Listener listener(event_loop, pool.get(), event_loop);
    listener.ListenTCP(8000);

    event_loop.Dispatch();
} catch (...) {
    PrintException(std::current_exception());
    return EXIT_FAILURE;
}
<commit_msg>test/RunNgHttp2Server: indent with tabs<commit_after>/*
 * Copyright 2007-2019 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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
 * FOUNDATION 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 "nghttp2/Server.hxx"
#include "http/Headers.hxx"
#include "http/IncomingRequest.hxx"
#include "http_server/Handler.hxx"
#include "event/Loop.hxx"
#include "event/net/TemplateServerSocket.hxx"
#include "net/UniqueSocketDescriptor.hxx"
#include "util/PrintException.hxx"
#include "pool/RootPool.hxx"
#include "fb_pool.hxx"

class Connection final
	: public boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::auto_unlink>>,
	  HttpServerConnectionHandler
{
	NgHttp2::ServerConnection http;

public:
	Connection(struct pool &pool, EventLoop &event_loop,
		   UniqueSocketDescriptor fd, SocketAddress address)
		:http(pool, event_loop, std::move(fd), FD_TCP, nullptr,
		      address,
		      *this) {}

	/* virtual methods from class HttpServerConnectionHandler */
	void HandleHttpRequest(IncomingHttpRequest &request,
			       const StopwatchPtr &,
			       CancellablePointer &cancel_ptr) noexcept override {
		(void)cancel_ptr;
		// TODO

		if (request.body)
			request.SendResponse(HTTP_STATUS_OK, {},
					     std::move(request.body));
		else
			request.SendMessage(HTTP_STATUS_OK, "Hello, world!\n");
	}

	void LogHttpRequest(IncomingHttpRequest &,
			    http_status_t, off_t,
			    uint64_t,
			    uint64_t) noexcept override {}

	void HttpConnectionError(std::exception_ptr e) noexcept override {
		PrintException(e);
		delete this;
	}

	void HttpConnectionClosed() noexcept override {
		delete this;
	}
};

typedef TemplateServerSocket<Connection, struct pool &,
			     EventLoop &> Listener;

int
main(int, char **) noexcept
try {
	const ScopeFbPoolInit fb_pool_init;
	RootPool pool;
	EventLoop event_loop;

	Listener listener(event_loop, pool.get(), event_loop);
	listener.ListenTCP(8000);

	event_loop.Dispatch();
} catch (...) {
	PrintException(std::current_exception());
	return EXIT_FAILURE;
}
<|endoftext|>


<commit_before>// Copyright 2019 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef _FASTDDS_SHAREDMEM_MPC_RINGBUFFER_
#define _FASTDDS_SHAREDMEM_MPC_RINGBUFFER_

#include <atomic>
#include <memory>
#include <cstdlib>

namespace eprosima {
namespace fastdds {
namespace rtps {

/**
 * Ring buffer capable of multiple producers / multiple consumers.
 * Read / Write operations are lock-free.
 * Data is organized in a fixed number of Cells of the same type.
 * Consumers (listeners) must be registered to access the cells.
 * When a Cell is pushed to the buffer, a counter for that cell is initialized with number
 * of listeners registered in the buffer in that moment. The Cell will be freed
 * when all listeners have poped the cell.
 */
template <class T>
class MultiProducerConsumerRingBuffer
{
public:

    class Cell
    {
    public:

        const T& data() const
        {
            return data_;
        }

        void data(
                const T& data)
        {
            data_ = data;
        }

        uint32_t ref_counter() const
        {
            return ref_counter_.load(std::memory_order_relaxed);
        }

        friend class MultiProducerConsumerRingBuffer<T>;

        std::atomic<uint32_t> ref_counter_;
        T data_;
    };

    class Listener
    {
    public:

        Listener(
                MultiProducerConsumerRingBuffer<T>& buffer,
                uint32_t write_p)
            : buffer_(buffer)
            , read_p_(write_p)
        {
        }

        ~Listener()
        {
            buffer_.unregister_listener(*this);
        }

        /**
         * @returns the Cell at the read pointer or nullptr if the buffer is empty
         */
        Cell* head()
        {
            auto pointer = buffer_.node_->pointer_.load(std::memory_order_relaxed);

            // If local read_pointer and write_pointer are equal => buffer is empty for this listener
            if (read_p_ == pointer.write_p )
            {
                return nullptr;
            }

            auto cell = &buffer_.cells_[get_pointer_value(read_p_)];

            return cell->ref_counter() != 0 ? cell : nullptr;
        }

        /**
         * Decreases the ref_counter of the head cell,
         * if the counter reaches 0 the cell becomes dirty
         * and free_cells are incremented
         * @return true if the cell ref_counter is 0 after pop
         * @throw std::exception if buffer is empty
         */
        bool pop()
        {
            auto cell = head();

            if (!cell)
            {
                throw std::runtime_error("Buffer empty");
            }

            auto counter = cell->ref_counter_.fetch_sub(1);
            assert(counter > 0);

            // If all the listeners have read the cell
            if (counter == 1)
            {
                // Increase the free cells => increase the global read pointer
                auto pointer = buffer_.node_->pointer_.load(std::memory_order_relaxed);
                while (!buffer_.node_->pointer_.compare_exchange_weak(pointer,
                        { pointer.write_p, pointer.free_cells + 1 },
                        std::memory_order_release,
                        std::memory_order_relaxed))
                {
                }
            }

            // Increase the local read pointer
            read_p_ = buffer_.inc_pointer(read_p_);

            return (counter == 1);
        }

    private:

        MultiProducerConsumerRingBuffer<T>& buffer_;
        uint32_t read_p_;
    };

    struct Pointer
    {
        uint32_t write_p;
        uint32_t free_cells;
    };

    struct Node
    {
        alignas(8) std::atomic<Pointer> pointer_;
        uint32_t total_cells_;

        uint32_t registered_listeners_;
    };

    MultiProducerConsumerRingBuffer(
            Cell* cells_base,
            uint32_t total_cells)
        : cells_(cells_base)
        , is_node_owned_(true)
    {
        if (total_cells > (1u << 31u))
        {
            throw std::runtime_error("total_cells out of range");
        }

        node_ = new Node();
        init_node(node_, total_cells);

        // Init cells
        for (Cell* cell = &cells_[0]; cell < &cells_[total_cells]; cell++)
        {
            cell->ref_counter_.store(0, std::memory_order_relaxed);
        }
    }

    MultiProducerConsumerRingBuffer(
            Cell* cells_base,
            Node* node)
        : cells_(cells_base)
        , is_node_owned_(false)
    {
        node_ = node;
    }

    ~MultiProducerConsumerRingBuffer()
    {
        if (is_node_owned_)
        {
            delete node_;
        }
    }

    /**
     * Push a new element into the buffer initializing the cell's ref_counter,
     * @return true if there are listeners registered, false if no listeners => buffer not enqueued
     * @throw std::runtime_error if the buffer is full
     */
    bool push(
            const T& data)
    {
        // If no listeners the buffer is dropped
        if (node_->registered_listeners_ == 0)
        {
            return false;
        }

        auto pointer = node_->pointer_.load(std::memory_order_relaxed);

        // if free cells, increase the write pointer and decrease the free cells
        while (pointer.free_cells > 0 &&
                !node_->pointer_.compare_exchange_weak(pointer, {inc_pointer(pointer.write_p), pointer.free_cells-1},
                std::memory_order_release,
                std::memory_order_relaxed))
        {
        }

        if (pointer.free_cells == 0)
        {
            throw std::runtime_error("Buffer full");
        }

        auto& cell = cells_[get_pointer_value(pointer.write_p)];

        cell.data(data);
        cell.ref_counter_.store(node_->registered_listeners_, std::memory_order_release);

        return true;
    }

    bool is_buffer_full()
    {
        return (node_->pointer_.load(std::memory_order_relaxed).free_cells == 0);
    }

    bool is_buffer_empty()
    {
        return (node_->pointer_.load(std::memory_order_relaxed).free_cells == node_->total_cells_);
    }

    /**
     * Register a new listener (consumer)
     * The new listener's read pointer is equal to the ring-buffer write pointer at the registering moment.
     * @return A unique_ptr to the listener.
     * @remarks This operation is not lock-free with push() / pop() operations, so the upper layer is responsible
     * for the mutual exclusion handling.
     * The listener will be unregistered when the unique_ptr is destroyed.
     */
    std::unique_ptr<Listener> register_listener()
    {
        // The new listener's read pointer is the current write pointer
        auto listener = std::unique_ptr<Listener>(
            new Listener(
                *this, node_->pointer_.load(std::memory_order_relaxed).write_p));

        node_->registered_listeners_++;

        return listener;
    }

    static void init_node(
            Node* node,
            uint32_t total_cells)
    {
        if (total_cells > static_cast<uint32_t>((1 << 31)))
        {
            throw std::runtime_error("total_cells out of range");
        }

        node->total_cells_ = total_cells;
        node->registered_listeners_ = 0;
        node->pointer_.store({0,total_cells}, std::memory_order_relaxed);
    }

    /**
     * Copies the currenty enqueued cells to a vector
     * @param [out] enqueued_cells pointers vector to where cells will be copied.
     * @remark This is an unsafe operation, that means the caller must assure
     * that no write operations are performed on the buffer while executing the copy.
     */
    void copy(
            std::vector<const T*>* enqueued_cells)
    {
        if (node_->registered_listeners_ > 0)
        {
            auto pointer = node_->pointer_.load(std::memory_order_relaxed);

            uint32_t p = pointer_to_head(pointer);

            while (p != pointer.write_p)
            {
                auto cell = &cells_[get_pointer_value(p)];

                // If the cell has not been read by any listener
                if (cell->ref_counter() > 0)
                {
                    enqueued_cells->push_back(&cell->data());
                }

                p = inc_pointer(p);
            }
        }
    }

private:

    Node* node_;
    Cell* cells_;
    bool is_node_owned_;

    static uint32_t get_pointer_value(
            uint32_t pointer)
    {
        // Bit 31 is loop_flag, 0-30 are value
        return pointer & 0x7FFFFFFF;
    }

    uint32_t inc_pointer(
            const uint32_t pointer) const
    {
        uint32_t value = pointer & 0x7FFFFFFF;
        uint32_t loop_flag = pointer >> 31;

        value = (value + 1) % node_->total_cells_;

        if (value == 0)
        {
            loop_flag ^= 1;
        }

        // Bit 31 is loop_flag, 0-30 are value
        return (loop_flag << 31) | value;
    }

    uint32_t pointer_to_head(
            const Pointer& pointer) const
    {
        // Init the head as write pointer in previous loop
        uint32_t head = pointer.write_p ^ 0x80000000;

        uint32_t value = head & 0x7FFFFFFF;
        uint32_t loop_flag = head >> 31;

        if (value +  pointer.free_cells >= node_->total_cells_)
        {
            loop_flag ^= 1;
        }

        // Skip the free cells
        value = (value + pointer.free_cells) % node_->total_cells_;

        // Bit 31 is loop_flag, 0-30 are value
        return (loop_flag << 31) | value;
    }

    /**
     * Unregister a listener.
     * @param listener Reference to the listener to unregister.
     * @remarks This operation is not lock-free with push() / pop() operations, so the upper layer is responsible.
     */
    void unregister_listener(
            Listener& listener)
    {
        try
        {
            // Forces to decrement the ref_counters for cells available to the listener.
            // A exception will break the loop
            while (1)
            {
                listener.pop();
            }

        }
        catch (const std::exception&)
        {
        }

        node_->registered_listeners_--;
    }
};

} // namespace rtps
} // namespace fastdds
} // namespace eprosima

#endif // _FASTDDS_SHAREDMEM_MPC_RINGBUFFER_<commit_msg>Avoid using a custom atomic type for shared pointer data (#1826)<commit_after>// Copyright 2019 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef _FASTDDS_SHAREDMEM_MPC_RINGBUFFER_
#define _FASTDDS_SHAREDMEM_MPC_RINGBUFFER_

#include <atomic>
#include <memory>
#include <cstdlib>

namespace eprosima {
namespace fastdds {
namespace rtps {

/**
 * Ring buffer capable of multiple producers / multiple consumers.
 * Read / Write operations are lock-free.
 * Data is organized in a fixed number of Cells of the same type.
 * Consumers (listeners) must be registered to access the cells.
 * When a Cell is pushed to the buffer, a counter for that cell is initialized with number
 * of listeners registered in the buffer in that moment. The Cell will be freed
 * when all listeners have poped the cell.
 */
template <class T>
class MultiProducerConsumerRingBuffer
{
public:

    class Cell
    {
    public:

        const T& data() const
        {
            return data_;
        }

        void data(
                const T& data)
        {
            data_ = data;
        }

        uint32_t ref_counter() const
        {
            return ref_counter_.load(std::memory_order_relaxed);
        }

        friend class MultiProducerConsumerRingBuffer<T>;

        std::atomic<uint32_t> ref_counter_;
        T data_;
    };

    class Listener
    {
    public:

        Listener(
                MultiProducerConsumerRingBuffer<T>& buffer,
                uint32_t write_p)
            : buffer_(buffer)
            , read_p_(write_p)
        {
        }

        ~Listener()
        {
            buffer_.unregister_listener(*this);
        }

        /**
         * @returns the Cell at the read pointer or nullptr if the buffer is empty
         */
        Cell* head()
        {
            auto pointer = buffer_.node_->pointer_.load(std::memory_order_relaxed);

            // If local read_pointer and write_pointer are equal => buffer is empty for this listener
            if (read_p_ == pointer.ptr.write_p )
            {
                return nullptr;
            }

            auto cell = &buffer_.cells_[get_pointer_value(read_p_)];

            return cell->ref_counter() != 0 ? cell : nullptr;
        }

        /**
         * Decreases the ref_counter of the head cell,
         * if the counter reaches 0 the cell becomes dirty
         * and free_cells are incremented
         * @return true if the cell ref_counter is 0 after pop
         * @throw std::exception if buffer is empty
         */
        bool pop()
        {
            auto cell = head();

            if (!cell)
            {
                throw std::runtime_error("Buffer empty");
            }

            auto counter = cell->ref_counter_.fetch_sub(1);
            assert(counter > 0);

            // If all the listeners have read the cell
            if (counter == 1)
            {
                // Increase the free cells => increase the global read pointer
                auto pointer = buffer_.node_->pointer_.load(std::memory_order_relaxed);
                while (!buffer_.node_->pointer_.compare_exchange_weak(pointer,
                        { { pointer.ptr.write_p, pointer.ptr.free_cells + 1 } },
                        std::memory_order_release,
                        std::memory_order_relaxed))
                {
                }
            }

            // Increase the local read pointer
            read_p_ = buffer_.inc_pointer(read_p_);

            return (counter == 1);
        }

    private:

        MultiProducerConsumerRingBuffer<T>& buffer_;
        uint32_t read_p_;
    };

    // std::atomic<> can only be used on lock-free primitive types with shared mem
    union PtrType
    {
        struct Pointer
        {
            uint32_t write_p;
            uint32_t free_cells;
        }
        ptr;
        uint64_t u;
    };

    struct Node
    {
        alignas(8) std::atomic<PtrType> pointer_;
        uint32_t total_cells_;

        uint32_t registered_listeners_;
    };

    MultiProducerConsumerRingBuffer(
            Cell* cells_base,
            uint32_t total_cells)
        : cells_(cells_base)
        , is_node_owned_(true)
    {
        if (total_cells > (1u << 31u))
        {
            throw std::runtime_error("total_cells out of range");
        }

        node_ = new Node();
        init_node(node_, total_cells);

        // Init cells
        for (Cell* cell = &cells_[0]; cell < &cells_[total_cells]; cell++)
        {
            cell->ref_counter_.store(0, std::memory_order_relaxed);
        }
    }

    MultiProducerConsumerRingBuffer(
            Cell* cells_base,
            Node* node)
        : cells_(cells_base)
        , is_node_owned_(false)
    {
        node_ = node;
    }

    ~MultiProducerConsumerRingBuffer()
    {
        if (is_node_owned_)
        {
            delete node_;
        }
    }

    /**
     * Push a new element into the buffer initializing the cell's ref_counter,
     * @return true if there are listeners registered, false if no listeners => buffer not enqueued
     * @throw std::runtime_error if the buffer is full
     */
    bool push(
            const T& data)
    {
        // If no listeners the buffer is dropped
        if (node_->registered_listeners_ == 0)
        {
            return false;
        }

        auto pointer = node_->pointer_.load(std::memory_order_relaxed);

        // if free cells, increase the write pointer and decrease the free cells
        while (pointer.ptr.free_cells > 0 &&
                !node_->pointer_.compare_exchange_weak(pointer,
                { { inc_pointer(pointer.ptr.write_p), pointer.ptr.free_cells - 1 } },
                std::memory_order_release,
                std::memory_order_relaxed))
        {
        }

        if (pointer.ptr.free_cells == 0)
        {
            throw std::runtime_error("Buffer full");
        }

        auto& cell = cells_[get_pointer_value(pointer.ptr.write_p)];

        cell.data(data);
        cell.ref_counter_.store(node_->registered_listeners_, std::memory_order_release);

        return true;
    }

    bool is_buffer_full()
    {
        return (node_->pointer_.load(std::memory_order_relaxed).ptr.free_cells == 0);
    }

    bool is_buffer_empty()
    {
        return (node_->pointer_.load(std::memory_order_relaxed).ptr.free_cells == node_->total_cells_);
    }

    /**
     * Register a new listener (consumer)
     * The new listener's read pointer is equal to the ring-buffer write pointer at the registering moment.
     * @return A unique_ptr to the listener.
     * @remarks This operation is not lock-free with push() / pop() operations, so the upper layer is responsible
     * for the mutual exclusion handling.
     * The listener will be unregistered when the unique_ptr is destroyed.
     */
    std::unique_ptr<Listener> register_listener()
    {
        // The new listener's read pointer is the current write pointer
        auto listener = std::unique_ptr<Listener>(
            new Listener(
                *this, node_->pointer_.load(std::memory_order_relaxed).ptr.write_p));

        node_->registered_listeners_++;

        return listener;
    }

    static void init_node(
            Node* node,
            uint32_t total_cells)
    {
        if (total_cells > static_cast<uint32_t>((1 << 31)))
        {
            throw std::runtime_error("total_cells out of range");
        }

        node->total_cells_ = total_cells;
        node->registered_listeners_ = 0;
        node->pointer_.store({ { 0, total_cells } }, std::memory_order_relaxed);
    }

    /**
     * Copies the currenty enqueued cells to a vector
     * @param [out] enqueued_cells pointers vector to where cells will be copied.
     * @remark This is an unsafe operation, that means the caller must assure
     * that no write operations are performed on the buffer while executing the copy.
     */
    void copy(
            std::vector<const T*>* enqueued_cells)
    {
        if (node_->registered_listeners_ > 0)
        {
            auto pointer = node_->pointer_.load(std::memory_order_relaxed);

            uint32_t p = pointer_to_head(pointer);

            while (p != pointer.ptr.write_p)
            {
                auto cell = &cells_[get_pointer_value(p)];

                // If the cell has not been read by any listener
                if (cell->ref_counter() > 0)
                {
                    enqueued_cells->push_back(&cell->data());
                }

                p = inc_pointer(p);
            }
        }
    }

private:

    Node* node_;
    Cell* cells_;
    bool is_node_owned_;

    static uint32_t get_pointer_value(
            uint32_t pointer)
    {
        // Bit 31 is loop_flag, 0-30 are value
        return pointer & 0x7FFFFFFF;
    }

    uint32_t inc_pointer(
            const uint32_t pointer) const
    {
        uint32_t value = pointer & 0x7FFFFFFF;
        uint32_t loop_flag = pointer >> 31;

        value = (value + 1) % node_->total_cells_;

        if (value == 0)
        {
            loop_flag ^= 1;
        }

        // Bit 31 is loop_flag, 0-30 are value
        return (loop_flag << 31) | value;
    }

    uint32_t pointer_to_head(
            const PtrType& pointer) const
    {
        // Init the head as write pointer in previous loop
        uint32_t head = pointer.ptr.write_p ^ 0x80000000;

        uint32_t value = head & 0x7FFFFFFF;
        uint32_t loop_flag = head >> 31;

        if (value +  pointer.ptr.free_cells >= node_->total_cells_)
        {
            loop_flag ^= 1;
        }

        // Skip the free cells
        value = (value + pointer.ptr.free_cells) % node_->total_cells_;

        // Bit 31 is loop_flag, 0-30 are value
        return (loop_flag << 31) | value;
    }

    /**
     * Unregister a listener.
     * @param listener Reference to the listener to unregister.
     * @remarks This operation is not lock-free with push() / pop() operations, so the upper layer is responsible.
     */
    void unregister_listener(
            Listener& listener)
    {
        try
        {
            // Forces to decrement the ref_counters for cells available to the listener.
            // A exception will break the loop
            while (1)
            {
                listener.pop();
            }

        }
        catch (const std::exception&)
        {
        }

        node_->registered_listeners_--;
    }

};

} // namespace rtps
} // namespace fastdds
} // namespace eprosima

#endif // _FASTDDS_SHAREDMEM_MPC_RINGBUFFER_
<|endoftext|>


<commit_before>//This file is released under terms of BSD license`
//See LICENSE.txt for more information

#include <unistd.h>    /* for getopt */
#include <algorithm>   /* for max, min */
#include <cmath>       /* for abs */
#include <iostream>    /* for cout */
#include <iomanip>     /* for std::setw */

#include "serializer/Serializer.h"
#include "shared.h"

using std::vector;
using std::string;
using namespace ser;

bool compareInfo(const DataFieldInfo& info1, const DataFieldInfo& info2)
{
	bool equal = true;
	if (info1.type() != info2.type())
	{
		equal = false;
		std::cout << "Type: " << info1.type() << " != " << info2.type() << std::endl;
	}
	if (info1.rank() != info2.rank())
	{
		equal = false;
		std::cout << "Rank: " << info1.rank() << " != " << info2.rank() << std::endl;
	}
	if (info1.bytesPerElement() != info2.bytesPerElement())
	{
		equal = false;
		std::cout << "Bytes per Element: " << info1.bytesPerElement() << " != " << info2.bytesPerElement() << std::endl;
	}
	if (info1.iSize() != info2.iSize())
	{
		equal = false;
		std::cout << "iSize: " << info1.iSize() << " != " << info2.iSize() << std::endl;
	}
	if (info1.jSize() != info2.jSize())
	{
		equal = false;
		std::cout << "jSize: " << info1.jSize() << " != " << info2.jSize() << std::endl;
	}
	if (info1.kSize() != info2.kSize())
	{
		equal = false;
		std::cout << "kSize: " << info1.kSize() << " != " << info2.kSize() << std::endl;
	}
	if (info1.lSize() != info2.lSize())
	{
		equal = false;
		std::cout << "lSize: " << info1.lSize() << " != " << info2.lSize() << std::endl;
	}

	return equal;
}

template <typename T>
bool compareData(const Serializer& serializer1, const Serializer& serializer2,
                 const Savepoint& savepoint,
                 const DataFieldInfo& info1, const DataFieldInfo& info2,
                 const IJKLBounds& bounds,
                 double tolerance, vector<bool>& failed)
{
	T* data1;
	readData(serializer1, info1, savepoint, data1);

	T* data2;
	readData(serializer2, info2, savepoint, data2);

	int iSize = info1.iSize();
	int jSize = info1.jSize();
	int kSize = info1.kSize();
	int lSize = info1.lSize();

	bool notequal = false;
	failed.resize(iSize * jSize * kSize * lSize);

	for (int i = bounds.iLower; i <= bounds.iUpper; ++i)
		for (int j = bounds.jLower; j <= bounds.jUpper; ++j)
			for (int k = bounds.kLower; k <= bounds.kUpper; ++k)
				for (int l = bounds.lLower; l <= bounds.lUpper; ++l)
				{
					int index = i * jSize * kSize * lSize + j * kSize * lSize + k * lSize + l;

					const double val = static_cast<double>(data1[index]);
					const double ref = static_cast<double>(data2[index]);
					const double err = std::fabs(ref) > 1. ?
					                 std::fabs((ref - val) / ref) : std::fabs(ref - val);

					const bool f = err > tolerance                     // Error is too large (e.g. val is infinite, ref is not)
					               || ((val != val) != (ref != ref))       // Exactly one is NaN
					               || (err != err && ref != val)           // ref is infinite, val different
					               ;
					failed[index] = f;
					notequal = notequal || f;
				}

	delete [] data1;
	delete [] data2;

	return !notequal;
}

template <typename T>
void printDifference(const Serializer& serializer1, const Serializer& serializer2,
                     const Savepoint& savepoint,
                     const DataFieldInfo& info1, const DataFieldInfo& info2,
                     const IJKLBounds& bounds,
                     const vector<bool>& failed)
{
	T* data1;
	readData(serializer1, info1, savepoint, data1);

	T* data2;
	readData(serializer2, info2, savepoint, data2);

	int iSize = info1.iSize();
	int jSize = info1.jSize();
	int kSize = info1.kSize();
	int lSize = info1.lSize();

	int nValues = (bounds.iUpper - bounds.iLower + 1) * (bounds.jUpper - bounds.jLower + 1) *
	              (bounds.kUpper - bounds.kLower + 1) * (bounds.lUpper - bounds.lLower + 1);
	int nErrors = 0;
	unsigned int nNan = 0;

	double maxRelError = 0;
	double maxAbsError = 0;

	for (int i = bounds.iLower; i <= bounds.iUpper; ++i)
		for (int j = bounds.jLower; j <= bounds.jUpper; ++j)
			for (int k = bounds.kLower; k <= bounds.kUpper; ++k)
				for (int l = bounds.lLower; l <= bounds.lUpper; ++l)
				{
					int index = i * jSize * kSize * lSize + j * kSize * lSize + k * lSize + l;
					if (failed[index])
					{
						++nErrors;

						const double val = static_cast<double>(data1[index]);
						const double ref = static_cast<double>(data2[index]);

						if ((val != val) || (ref != ref)) ++nNan;
						maxAbsError = std::max(maxAbsError, std::fabs(val - ref));
						maxRelError = std::max(maxRelError, std::fabs((val - ref) / ref));
					}
				}

	std::cout << " | Number of values: " << std::setw(6) << nValues << "\n";
	std::cout << " | Number of errors: " << std::setw(6) << nErrors << "\n";
	if (nNan > 0) std::cout << " | Number of NaN errors: " << std::setw(6) << nNan << "\n";
	std::cout << " | Percentuage of errors: " << std::setprecision(2) << std::fixed << (100.*nErrors) / nValues << " %\n";
	std::cout << " | Maximum absolute error: " << std::setw(17) << std::setfill(' ') << std::scientific << std::setprecision(10) << maxAbsError  << "\n";
	std::cout << " | Maximum relative error: " << std::setw(17) << std::setfill(' ') << std::scientific << std::setprecision(10) << maxRelError  << "\n";

	delete [] data1;
	delete [] data2;

}

int compare(const std::string& directory1, const std::string& basename1,
            const std::string& directory2, const std::string& basename2,
            const Bounds& iBounds, const Bounds& jBounds,
            const Bounds& kBounds, const Bounds& lBounds,
            double tolerance, bool infoOnly, const vector<string>& specificFields)

{
	Serializer serializer1;
	serializer1.Init(directory1, basename1, SerializerOpenModeRead);

	Serializer serializer2;
	serializer2.Init(directory2, basename2, SerializerOpenModeRead);

	vector<Savepoint> savepoints = serializer1.savepoints();

	bool hasDifferences = false;

	for (int i = 0; i < savepoints.size(); i++)
	{
		if (savepoints[i].name().substr(savepoints[i].name().size() - 4, 4) != "-out")
			continue;

		std::cout << "---------------------------------" << std::endl;
		std::cout << savepoints[i].name()                << std::endl;
		std::cout << savepoints[i].metainfo().ToString() << std::endl;

		vector<string> fieldsAtSavepoint = serializer1.FieldsAtSavepoint(savepoints[i]);
		vector<string> fields;

		if (specificFields.empty())
			fields = serializer1.FieldsAtSavepoint(savepoints[i]);
		else
		{
			fields.resize(std::min(specificFields.size(), fieldsAtSavepoint.size()));
			auto it = std::set_intersection(fieldsAtSavepoint.begin(), fieldsAtSavepoint.end(),
			                                specificFields.begin(), specificFields.end(), fields.begin());
			fields.resize(it - fields.begin());
		}

		for (auto const& field : fields)
		{
			std::cout << '\t' << field << std::endl;

			DataFieldInfo info1 = serializer1.FindField(field);
			DataFieldInfo info2 = serializer2.FindField(field);

			IJKLBounds bounds = getIJKLBounds(info1, iBounds, jBounds, kBounds, lBounds);

			bool equal = compareInfo(info1, info2);
			if (!equal)
			{
				return 1;
			}
			else if (infoOnly)
			{
				continue;
			}

			vector<bool> failed;

			if (info1.type() == "integer" || info1.type() == "int")
			{
				equal = compareData<int>(serializer1, serializer2, savepoints[i], info1, info2, bounds, tolerance, failed);
				if (!equal)
					printDifference<int>(serializer1, serializer2, savepoints[i], info1, info2, bounds, failed);
			}
			else if (info1.type() == "double")
			{
				equal = compareData<double>(serializer1, serializer2, savepoints[i], info1, info2, bounds, tolerance, failed);
				if (!equal)
					printDifference<double>(serializer1, serializer2, savepoints[i], info1, info2, bounds, failed);
			}
			else if (info1.type() == "float")
			{
				equal = compareData<float>(serializer1, serializer2, savepoints[i], info1, info2, bounds, tolerance, failed);
				if (!equal)
					printDifference<float>(serializer1, serializer2, savepoints[i], info1, info2, bounds, failed);
			}
			else
			{
				std::cerr << "Unsupported type: " << info1.type() << std::endl;
				return 2;
			}
			hasDifferences = hasDifferences | !equal;
		}
	}

	if (hasDifferences)
	{
		return 1;
	}
	return 0;
}

void printHelp()
{
	std::cout << "Usage:" << std::endl;
	std::cout << "  compare [options] field_file1 field_file2" << std::endl;
	std::cout << "  compare [options] json_file1 json_file2" << std::endl;
	std::cout << "  compare -h" << std::endl;
	std::cout << "Options:" << std::endl;
	std::cout << "  -h                       show this screen" << std::endl;
	std::cout << "  -q                       compare field description only" << std::endl;
	std::cout << "  -t <tol>                 tolerance, default 1e-12" << std::endl;
	std::cout << "  -i <iDim>                compare <iDim> for i dimension" << std::endl;
	std::cout << "  -i <iLower>:<iUpper>     compare range <iLower>:<iUpper> for i dimension" << std::endl;
	std::cout << "  -j <jDim>                compare <jDim> for j dimension" << std::endl;
	std::cout << "  -j <jLower>:<jUpper>     compare range <jLower>:<jUpper> for j dimension" << std::endl;
	std::cout << "  -k <kDim>                compare <kDim> for k dimension" << std::endl;
	std::cout << "  -k <kLower>:<kUpper>     compare range <kLower>:<kUpper> for k dimension" << std::endl;
	std::cout << "  -l <lDim>                compare <lDim> for l dimension" << std::endl;
	std::cout << "  -l <lLower>:<lUpper>     compare range <lLower>:<lUpper> for l dimension" << std::endl;

}

int main (int argc, char **argv)
{
	if (argc < 2)
	{
		printHelp();
		return 0;
	}

	int opt;
	std::string i = ":";
	std::string j = ":";
	std::string k = ":";
	std::string l = ":";
	double tolerance = 1e-12;
	std::string savepointName2 = "";
	bool infoOnly = false;
	while ( (opt = getopt(argc, argv, "i:j:k:l:t:q:h")) != -1) {
		switch (opt)
		{
		case 'i':
			i = optarg;
			break;
		case 'j':
			j = optarg;
			break;
		case 'k':
			k = optarg;
			break;
		case 'l':
			l = optarg;
			break;
		case 't':
			tolerance = strtod(optarg, NULL);
			break;
		case 'q':
			infoOnly = true;
			break;
		case 'h':
			printHelp();
			return 0;
		}
	}

	Bounds iBounds = string2bounds(i);
	Bounds jBounds = string2bounds(j);
	Bounds kBounds = string2bounds(k);
	Bounds lBounds = string2bounds(l);

	std::string filepath1 = argv[optind++];
	std::string filepath2 = argv[optind++];

	vector<string> specificFields;

	std::string directory1;
	std::string basename1;
	std::string field1;
	if (!splitFilePath(filepath1, directory1, basename1, field1))
	{
		std::cerr << "Invalid file 1: " << filepath1 << std::endl;
		return 2;
	}

	std::string directory2;
	std::string basename2;
	std::string field2;
	if (!splitFilePath(filepath2, directory2, basename2, field2))
	{
		std::cerr << "Invalid file 2: " << filepath2 << std::endl;
		return 2;
	}

	if (field1 != field2)
	{
		std::cerr << "inconsistent fields" << std::endl;
		return 2;
	}

	if (field1 != "")
		specificFields.push_back(field1);

	std::cout << basename1 << std::endl << basename2 << std::endl;

	return compare(directory1, basename1,
	               directory2, basename2,
	               iBounds, jBounds, kBounds, lBounds, tolerance,
	               infoOnly, specificFields);

}
<commit_msg>Remove unholy tabs for spaces and format a bit<commit_after>//This file is released under terms of BSD license`
//See LICENSE.txt for more information

#include <unistd.h>    /* for getopt */
#include <algorithm>   /* for max, min */
#include <cmath>       /* for abs */
#include <iostream>    /* for cout */
#include <iomanip>     /* for std::setw */

#include "serializer/Serializer.h"
#include "shared.h"

using std::vector;
using std::string;
using namespace ser;

bool compareInfo(const DataFieldInfo& info1, const DataFieldInfo& info2)
{
    bool equal = true;
    if (info1.type() != info2.type()) {
        equal = false;
        std::cout << "Type: " << info1.type() << " != " << info2.type() << std::endl;
    }
    if (info1.rank() != info2.rank()) {
        equal = false;
        std::cout << "Rank: " << info1.rank() << " != " << info2.rank() << std::endl;
    }
    if (info1.bytesPerElement() != info2.bytesPerElement()) {
        equal = false;
        std::cout << "Bytes per Element: " << info1.bytesPerElement() << " != " << info2.bytesPerElement() << std::endl;
    }
    if (info1.iSize() != info2.iSize()) {
        equal = false;
        std::cout << "iSize: " << info1.iSize() << " != " << info2.iSize() << std::endl;
    }
    if (info1.jSize() != info2.jSize()) {
        equal = false;
        std::cout << "jSize: " << info1.jSize() << " != " << info2.jSize() << std::endl;
    }
    if (info1.kSize() != info2.kSize()) {
        equal = false;
        std::cout << "kSize: " << info1.kSize() << " != " << info2.kSize() << std::endl;
    }
    if (info1.lSize() != info2.lSize()) {
        equal = false;
        std::cout << "lSize: " << info1.lSize() << " != " << info2.lSize() << std::endl;
    }

    return equal;
}

template <typename T>
bool compareData(const Serializer& serializer1, const Serializer& serializer2,
                 const Savepoint& savepoint,
                 const DataFieldInfo& info1, const DataFieldInfo& info2,
                 const IJKLBounds& bounds,
                 double tolerance, vector<bool>& failed)
{
    T* data1;
    readData(serializer1, info1, savepoint, data1);

    T* data2;
    readData(serializer2, info2, savepoint, data2);

    int iSize = info1.iSize();
    int jSize = info1.jSize();
    int kSize = info1.kSize();
    int lSize = info1.lSize();

    bool notequal = false;
    failed.resize(iSize * jSize * kSize * lSize);

    for (int i = bounds.iLower; i <= bounds.iUpper; ++i) {
        for (int j = bounds.jLower; j <= bounds.jUpper; ++j) {
            for (int k = bounds.kLower; k <= bounds.kUpper; ++k) {
                for (int l = bounds.lLower; l <= bounds.lUpper; ++l) {
                    int index = i * jSize * kSize * lSize + j * kSize * lSize + k * lSize + l;

                    const double val = static_cast<double>(data1[index]);
                    const double ref = static_cast<double>(data2[index]);
                    const double err = std::fabs(ref) > 1. ?
                                       std::fabs((ref - val) / ref) : std::fabs(ref - val);

                    const bool f = err > tolerance         // Error is too large (e.g. val is infinite, ref is not)
                        || ((val != val) != (ref != ref))  // Exactly one is NaN
                        || (err != err && ref != val);     // ref is infinite, val different

                    failed[index] = f;
                    notequal = notequal || f;
                }
            }
        }
    }

    delete [] data1;
    delete [] data2;

    return !notequal;
}

template <typename T>
void printDifference(const Serializer& serializer1, const Serializer& serializer2,
                     const Savepoint& savepoint,
                     const DataFieldInfo& info1, const DataFieldInfo& info2,
                     const IJKLBounds& bounds,
                     const vector<bool>& failed)
{
    T* data1;
    readData(serializer1, info1, savepoint, data1);

    T* data2;
    readData(serializer2, info2, savepoint, data2);

    int iSize = info1.iSize();
    int jSize = info1.jSize();
    int kSize = info1.kSize();
    int lSize = info1.lSize();

    int nValues = (bounds.iUpper - bounds.iLower + 1) * (bounds.jUpper - bounds.jLower + 1) *
                  (bounds.kUpper - bounds.kLower + 1) * (bounds.lUpper - bounds.lLower + 1);
    int nErrors = 0;
    unsigned int nNan = 0;

    double maxRelError = 0;
    double maxAbsError = 0;

    for (int i = bounds.iLower; i <= bounds.iUpper; ++i) {
        for (int j = bounds.jLower; j <= bounds.jUpper; ++j) {
            for (int k = bounds.kLower; k <= bounds.kUpper; ++k) {
                for (int l = bounds.lLower; l <= bounds.lUpper; ++l) {
                    int index = i * jSize * kSize * lSize + j * kSize * lSize + k * lSize + l;
                    if (failed[index]) {
                        ++nErrors;

                        const double val = static_cast<double>(data1[index]);
                        const double ref = static_cast<double>(data2[index]);

                        if ((val != val) || (ref != ref)) {
                            ++nNan;
                        }
                        maxAbsError = std::max(maxAbsError, std::fabs(val - ref));
                        maxRelError = std::max(maxRelError, std::fabs((val - ref) / ref));
                    }
                }
            }
        }
    }

    std::cout << " | Number of values: " << std::setw(6) << nValues << "\n";
    std::cout << " | Number of errors: " << std::setw(6) << nErrors << "\n";
    if (nNan > 0) std::cout << " | Number of NaN errors: " << std::setw(6) << nNan << "\n";
    std::cout << " | Percentuage of errors: " << std::setprecision(2) << std::fixed << (100.*nErrors) / nValues << " %\n";
    std::cout << " | Maximum absolute error: " << std::setw(17) << std::setfill(' ') << std::scientific << std::setprecision(10) << maxAbsError  << "\n";
    std::cout << " | Maximum relative error: " << std::setw(17) << std::setfill(' ') << std::scientific << std::setprecision(10) << maxRelError  << "\n";

    delete [] data1;
    delete [] data2;

}

int compare(const std::string& directory1, const std::string& basename1,
            const std::string& directory2, const std::string& basename2,
            const Bounds& iBounds, const Bounds& jBounds,
            const Bounds& kBounds, const Bounds& lBounds,
            double tolerance, bool infoOnly, const vector<string>& specificFields)

{
    Serializer serializer1;
    serializer1.Init(directory1, basename1, SerializerOpenModeRead);

    Serializer serializer2;
    serializer2.Init(directory2, basename2, SerializerOpenModeRead);

    vector<Savepoint> savepoints = serializer1.savepoints();

    bool hasDifferences = false;

    for (int i = 0; i < savepoints.size(); i++)
    {
        if (savepoints[i].name().substr(savepoints[i].name().size() - 4, 4) != "-out")
            continue;

        std::cout << "---------------------------------" << std::endl;
        std::cout << savepoints[i].name()                << std::endl;
        std::cout << savepoints[i].metainfo().ToString() << std::endl;

        vector<string> fieldsAtSavepoint = serializer1.FieldsAtSavepoint(savepoints[i]);
        vector<string> fields;

        if (specificFields.empty()) {

            fields = serializer1.FieldsAtSavepoint(savepoints[i]);
        } else {
            fields.resize(std::min(specificFields.size(), fieldsAtSavepoint.size()));
            auto it = std::set_intersection(fieldsAtSavepoint.begin(), fieldsAtSavepoint.end(),
                specificFields.begin(), specificFields.end(), fields.begin());
            fields.resize(it - fields.begin());
        }

        for (auto const& field : fields) {
            std::cout << '\t' << field << std::endl;

            DataFieldInfo info1 = serializer1.FindField(field);
            DataFieldInfo info2 = serializer2.FindField(field);

            IJKLBounds bounds = getIJKLBounds(info1, iBounds, jBounds, kBounds, lBounds);

            bool equal = compareInfo(info1, info2);
            if (!equal) {
                return 1;
            } else if (infoOnly) {
                continue;
            }

            vector<bool> failed;

            if (info1.type() == "integer" || info1.type() == "int") {
                equal = compareData<int>(serializer1, serializer2, savepoints[i], info1, info2, bounds, tolerance, failed);
                if (!equal) {
                    printDifference<int>(serializer1, serializer2, savepoints[i], info1, info2, bounds, failed);
                }
            } else if (info1.type() == "double") {
                equal = compareData<double>(serializer1, serializer2, savepoints[i], info1, info2, bounds, tolerance, failed);
                if (!equal) {
                    printDifference<double>(serializer1, serializer2, savepoints[i], info1, info2, bounds, failed);
                }
            } else if (info1.type() == "float") {
                equal = compareData<float>(serializer1, serializer2, savepoints[i], info1, info2, bounds, tolerance, failed);
                if (!equal) {
                    printDifference<float>(serializer1, serializer2, savepoints[i], info1, info2, bounds, failed);
                }
            } else {
                std::cerr << "Unsupported type: " << info1.type() << std::endl;
                return 2;
            }
            hasDifferences = hasDifferences | !equal;
        }
    }

    if (hasDifferences) {
        return 1;
    }
    return 0;
}

void printHelp()
{
    std::cout << "Usage:" << std::endl;
    std::cout << "  compare [options] field_file1 field_file2" << std::endl;
    std::cout << "  compare [options] json_file1 json_file2" << std::endl;
    std::cout << "  compare -h" << std::endl;
    std::cout << "Options:" << std::endl;
    std::cout << "  -h                       show this screen" << std::endl;
    std::cout << "  -q                       compare field description only" << std::endl;
    std::cout << "  -t <tol>                 tolerance, default 1e-12" << std::endl;
    std::cout << "  -i <iDim>                compare <iDim> for i dimension" << std::endl;
    std::cout << "  -i <iLower>:<iUpper>     compare range <iLower>:<iUpper> for i dimension" << std::endl;
    std::cout << "  -j <jDim>                compare <jDim> for j dimension" << std::endl;
    std::cout << "  -j <jLower>:<jUpper>     compare range <jLower>:<jUpper> for j dimension" << std::endl;
    std::cout << "  -k <kDim>                compare <kDim> for k dimension" << std::endl;
    std::cout << "  -k <kLower>:<kUpper>     compare range <kLower>:<kUpper> for k dimension" << std::endl;
    std::cout << "  -l <lDim>                compare <lDim> for l dimension" << std::endl;
    std::cout << "  -l <lLower>:<lUpper>     compare range <lLower>:<lUpper> for l dimension" << std::endl;
}

int main (int argc, char **argv)
{
    if (argc < 2) {
        printHelp();
        return 0;
    }

    int opt;
    std::string i = ":";
    std::string j = ":";
    std::string k = ":";
    std::string l = ":";
    double tolerance = 1e-12;
    std::string savepointName2 = "";
    bool infoOnly = false;
    while ( (opt = getopt(argc, argv, "i:j:k:l:t:q:h")) != -1) {
        switch (opt) {
            case 'i':
                i = optarg;
                break;
            case 'j':
                j = optarg;
                break;
            case 'k':
                k = optarg;
                break;
            case 'l':
                l = optarg;
                break;
            case 't':
                tolerance = strtod(optarg, NULL);
                break;
            case 'q':
                infoOnly = true;
                break;
            case 'h':
                printHelp();
                return 0;
        }
    }

    Bounds iBounds = string2bounds(i);
    Bounds jBounds = string2bounds(j);
    Bounds kBounds = string2bounds(k);
    Bounds lBounds = string2bounds(l);

    std::string filepath1 = argv[optind++];
    std::string filepath2 = argv[optind++];

    vector<string> specificFields;

    std::string directory1;
    std::string basename1;
    std::string field1;
    if (!splitFilePath(filepath1, directory1, basename1, field1)) {
        std::cerr << "Invalid file 1: " << filepath1 << std::endl;
        return 2;
    }

    std::string directory2;
    std::string basename2;
    std::string field2;
    if (!splitFilePath(filepath2, directory2, basename2, field2)) {
        std::cerr << "Invalid file 2: " << filepath2 << std::endl;
        return 2;
    }

    if (field1 != field2) {
        std::cerr << "inconsistent fields" << std::endl;
        return 2;
    }

    if (field1 != "") {
      specificFields.push_back(field1);
    }

    std::cout << basename1 << std::endl << basename2 << std::endl;

    return compare(directory1, basename1,
                   directory2, basename2,
                   iBounds, jBounds, kBounds, lBounds, tolerance,
                   infoOnly, specificFields);

}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/ocmb/odyssey/procedures/hwp/memory/ody_draminit_mc.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2021,2022                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file ody_mss_draminit_mc.C
/// @brief Initialize the memory controller to take over the DRAM
///
// *HWP HWP Owner: Louis Stermole <stermole@us.ibm.com>
// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 1
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <ody_draminit_mc.H>

extern "C"
{
///
/// @brief Initialize the MC now that DRAM is up
/// @param[in] i_target, the MC of the ports
/// @return FAPI2_RC_SUCCESS iff ok
///
    fapi2::ReturnCode ody_draminit_mc( const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target )
    {
        return fapi2::FAPI2_RC_SUCCESS;
    }
<commit_msg>porting ody_draminit_mc code<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/ocmb/odyssey/procedures/hwp/memory/ody_draminit_mc.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2021,2022                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file ody_mss_draminit_mc.C
/// @brief Initialize the memory controller to take over the DRAM
///
// *HWP HWP Owner: Louis Stermole <stermole@us.ibm.com>
// *HWP HWP Backup: Stephen Glancy <sglancy@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 1
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <ody_draminit_mc.H>

#include <generic/memory/lib/utils/c_str.H>
#include <generic/memory/lib/utils/find.H>
#include <generic/memory/lib/utils/count_dimm.H>

#include <lib/mc/ody_port_traits.H>
#include <generic/memory/lib/utils/mc/gen_mss_port.H>
#include <generic/memory/mss_git_data_helper.H>
#include <generic/memory/lib/utils/fir/gen_mss_unmask.H>

extern "C"
{
///
/// @brief Initialize the MC now that DRAM is up
/// @param[in] i_target, the MC of the ports
/// @return FAPI2_RC_SUCCESS iff ok
///
    fapi2::ReturnCode ody_draminit_mc( const fapi2::Target<fapi2::TARGET_TYPE_OCMB_CHIP>& i_target )
    {
        mss::display_git_commit_info("ody_draminit_mc");

        FAPI_INF( TARGTIDFORMAT " Start ody_draminit_mc", TARGTID );

        //skip this ocmb_chip if we have no DIMM's configured
        if(mss::count_dimm(i_target) == 0)
        {
            FAPI_INF( "No DIMM's configured on " TARGTIDFORMAT " Skipping this OCMB_CHIP.", TARGTID ) ;
            return fapi2::FAPI2_RC_SUCCESS;
        }

        // TODO Zen:MST-1405 Power management settings have changed in Odyssey. Need to update generic function
        // and traits to accommodate changes
        // Enable Power management based off of mrw_power_control_requested
        // FAPI_TRY( mss::enable_power_management<mss::mc_type::ODYSSEY>(i_target), "%s Failed to enable power management",
        //           mss::c_str(i_target) );

        // TODO Zen:MST-1406 Check with design team if we have an "init complete" indicator in Odyssey.
        // This was assigned to an unused (and unnamed) bit on Explorer PMU8Q.
        // Set the IML Complete bit. Steve Powell to find a bit in the SRQ to use for this purpose
        // FAPI_TRY( mss::change_iml_complete<mss::mc_type::ODYSSEY>(i_target, mss::HIGH), "%s Failed to set_ipm_complete",
        //           mss::c_str(i_target));

        // Set DFI init start requested from Stephen Powell
        FAPI_TRY( mss::change_dfi_init_start<mss::mc_type::ODYSSEY>(i_target, mss::ON ),
                  TARGTIDFORMAT " Failed to change_dfi_init_start",
                  TARGTID );

        // Start the refresh engines by setting MBAREF0Q(0) = 1. Note that the remaining bits in
        // MBAREF0Q should retain their initialization values.
        FAPI_TRY( mss::change_refresh_enable<mss::mc_type::ODYSSEY>(i_target, mss::HIGH),
                  TARGTIDFORMAT " Failed change_refresh_enable",
                  TARGTID );

        // Trigger the MC to take the DRAMs out of self refresh
        FAPI_TRY( mss::change_force_str<mss::mc_type::ODYSSEY>(i_target, mss::LOW), TARGTIDFORMAT " Failed change_force_str",
                  TARGTID );

        // Enable periodic short zq cal
        FAPI_TRY( mss::enable_zq_cal<mss::mc_type::ODYSSEY>(i_target), TARGTIDFORMAT " Failed enable_zq_cal", TARGTID );

        // Enable periodic mem calibration
        FAPI_TRY( mss::enable_periodic_cal<mss::mc_type::ODYSSEY>(i_target), TARGTIDFORMAT " Failed enable_periodic_cal",
                  TARGTID );

        // TODO Zen:MST-1529 Specialize unmask::after_draminit_mc for Odyssey
        // Unmask registers after draminit_mc
        // FAPI_TRY(mss::unmask::after_draminit_mc<mss::mc_type::ODYSSEY>(i_target), "%s Failed after_draminit_mc",
        //          mss::c_str(i_target));

        FAPI_INF( TARGTIDFORMAT " End ody_draminit MC", TARGTID );
        return fapi2::FAPI2_RC_SUCCESS;

    fapi_try_exit:
        return fapi2::current_err;
    }
}
<|endoftext|>


<commit_before>//===- opt.cpp - The LLVM Modular Optimizer -------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Optimizations may be specified an arbitrary number of times on the command
// line, They are run in the order specified.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/Assembly/Parser.h"
#include "llvm/PassManager.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/PassNameParser.h"
#include "llvm/System/Signals.h"
#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/SystemUtils.h"
#include "llvm/Support/Timer.h"
#include "llvm/LinkAllPasses.h"
#include "llvm/LinkAllVMCore.h"
#include <fstream>
#include <memory>
#include <algorithm>

using namespace llvm;

// The OptimizationList is automatically populated with registered Passes by the
// PassNameParser.
//
static cl::list<const PassInfo*, bool,
                FilteredPassNameParser<PassInfo::Optimization> >
OptimizationList(cl::desc("Optimizations available:"));

// Other command line options...
//
static cl::opt<std::string>
InputFilename(cl::Positional, cl::desc("<input bytecode file>"),
    cl::init("-"), cl::value_desc("filename"));

static cl::opt<std::string>
OutputFilename("o", cl::desc("Override output filename"),
               cl::value_desc("filename"), cl::init("-"));

static cl::opt<bool>
Force("f", cl::desc("Overwrite output files"));

static cl::opt<bool>
PrintEachXForm("p", cl::desc("Print module after each transformation"));

static cl::opt<bool>
NoOutput("disable-output",
         cl::desc("Do not write result bytecode file"), cl::Hidden);

static cl::opt<bool>
NoVerify("disable-verify", cl::desc("Do not verify result module"), cl::Hidden);

static cl::opt<bool>
Quiet("q", cl::desc("Obsolete option"), cl::Hidden);

static cl::alias
QuietA("quiet", cl::desc("Alias for -q"), cl::aliasopt(Quiet));

static cl::opt<bool>
AnalyzeOnly("analyze", cl::desc("Only perform analysis, no optimization"));

// The AnalysesList is automatically populated with registered Passes by the
// PassNameParser.
static
  cl::list<const PassInfo*, bool, FilteredPassNameParser<PassInfo::Analysis> >
  AnalysesList(cl::desc("Analyses available:"));

static Timer BytecodeLoadTimer("Bytecode Loader");

// ---------- Define Printers for module and function passes ------------
namespace {

struct ModulePassPrinter : public ModulePass {
  const PassInfo *PassToPrint;
  ModulePassPrinter(const PassInfo *PI) : PassToPrint(PI) {}

  virtual bool runOnModule(Module &M) {
    if (!Quiet) {
      std::cout << "Printing analysis '" << PassToPrint->getPassName()
                << "':\n";
      getAnalysisID<Pass>(PassToPrint).print(std::cout, &M);
    }

    // Get and print pass...
    return false;
  }

  virtual const char *getPassName() const { return "'Pass' Printer"; }

  virtual void getAnalysisUsage(AnalysisUsage &AU) const {
    AU.addRequiredID(PassToPrint);
    AU.setPreservesAll();
  }
};

struct FunctionPassPrinter : public FunctionPass {
  const PassInfo *PassToPrint;
  FunctionPassPrinter(const PassInfo *PI) : PassToPrint(PI) {}

  virtual bool runOnFunction(Function &F) {
    if (!Quiet) {
      std::cout << "Printing analysis '" << PassToPrint->getPassName()
		<< "' for function '" << F.getName() << "':\n";
    }
    // Get and print pass...
    getAnalysisID<Pass>(PassToPrint).print(std::cout, F.getParent());
    return false;
  }

  virtual const char *getPassName() const { return "FunctionPass Printer"; }

  virtual void getAnalysisUsage(AnalysisUsage &AU) const {
    AU.addRequiredID(PassToPrint);
    AU.setPreservesAll();
  }
};

struct BasicBlockPassPrinter : public BasicBlockPass {
  const PassInfo *PassToPrint;
  BasicBlockPassPrinter(const PassInfo *PI) : PassToPrint(PI) {}

  virtual bool runOnBasicBlock(BasicBlock &BB) {
    if (!Quiet) {
      std::cout << "Printing Analysis info for BasicBlock '" << BB.getName()
		<< "': Pass " << PassToPrint->getPassName() << ":\n";
    }

    // Get and print pass...
    getAnalysisID<Pass>(PassToPrint).print(
      std::cout, BB.getParent()->getParent());
    return false;
  }

  virtual const char *getPassName() const { return "BasicBlockPass Printer"; }

  virtual void getAnalysisUsage(AnalysisUsage &AU) const {
    AU.addRequiredID(PassToPrint);
    AU.setPreservesAll();
  }
};

} // anonymous namespace

//===----------------------------------------------------------------------===//
// main for opt
//
int main(int argc, char **argv) {
  try {
    cl::ParseCommandLineOptions(argc, argv,
      " llvm .bc -> .bc modular optimizer and analysis printer \n");
    sys::PrintStackTraceOnErrorSignal();

    if (AnalyzeOnly) {
      Module *CurMod = 0;
#if 0
      TimeRegion RegionTimer(BytecodeLoadTimer);
#endif
      CurMod = ParseBytecodeFile(InputFilename);
      ParseError Err;
      if (!CurMod && !(CurMod = ParseAssemblyFile(InputFilename,&Err))){
        std::cerr << argv[0] << ": " << Err.getMessage() << "\n";
        return 1;
      }

      // Create a PassManager to hold and optimize the collection of passes we
      // are about to build...
      PassManager Passes;

      // Add an appropriate TargetData instance for this module...
      Passes.add(new TargetData(CurMod));

      // Make sure the input LLVM is well formed.
      if (!NoVerify)
        Passes.add(createVerifierPass());

      // Create a new optimization pass for each one specified on the
      // command line
      for (unsigned i = 0; i < AnalysesList.size(); ++i) {
        const PassInfo *Analysis = AnalysesList[i];

        if (Analysis->getNormalCtor()) {
          Pass *P = Analysis->getNormalCtor()();
          Passes.add(P);

          if (BasicBlockPass *BBP = dynamic_cast<BasicBlockPass*>(P))
            Passes.add(new BasicBlockPassPrinter(Analysis));
          else if (FunctionPass *FP = dynamic_cast<FunctionPass*>(P))
            Passes.add(new FunctionPassPrinter(Analysis));
          else
            Passes.add(new ModulePassPrinter(Analysis));

        } else
          std::cerr << argv[0] << ": cannot create pass: "
                    << Analysis->getPassName() << "\n";
      }

      Passes.run(*CurMod);

      delete CurMod;
      return 0;
    }

    // Allocate a full target machine description only if necessary...
    // FIXME: The choice of target should be controllable on the command line.
    std::auto_ptr<TargetMachine> target;

    TargetMachine* TM = NULL;
    std::string ErrorMessage;

    // Load the input module...
    std::auto_ptr<Module> M(ParseBytecodeFile(InputFilename, &ErrorMessage));
    if (M.get() == 0) {
      std::cerr << argv[0] << ": ";
      if (ErrorMessage.size())
        std::cerr << ErrorMessage << "\n";
      else
        std::cerr << "bytecode didn't read correctly.\n";
      return 1;
    }

    // Figure out what stream we are supposed to write to...
    // FIXME: cout is not binary!
    std::ostream *Out = &std::cout;  // Default to printing to stdout...
    if (OutputFilename != "-") {
      if (!Force && std::ifstream(OutputFilename.c_str())) {
        // If force is not specified, make sure not to overwrite a file!
        std::cerr << argv[0] << ": error opening '" << OutputFilename
                  << "': file exists!\n"
                  << "Use -f command line argument to force output\n";
        return 1;
      }
      std::ios::openmode io_mode = std::ios::out | std::ios::trunc |
                                   std::ios::binary;
      Out = new std::ofstream(OutputFilename.c_str(), io_mode);

      if (!Out->good()) {
        std::cerr << argv[0] << ": error opening " << OutputFilename << "!\n";
        return 1;
      }

      // Make sure that the Output file gets unlinked from the disk if we get a
      // SIGINT
      sys::RemoveFileOnSignal(sys::Path(OutputFilename));
    }

    // If the output is set to be emitted to standard out, and standard out is a
    // console, print out a warning message and refuse to do it.  We don't
    // impress anyone by spewing tons of binary goo to a terminal.
    if (!Force && !NoOutput && CheckBytecodeOutputToConsole(Out,!Quiet)) {
      NoOutput = true;
    }

    // Create a PassManager to hold and optimize the collection of passes we are
    // about to build...
    //
    PassManager Passes;

    // Add an appropriate TargetData instance for this module...
    Passes.add(new TargetData(M.get()));

    // Create a new optimization pass for each one specified on the command line
    for (unsigned i = 0; i < OptimizationList.size(); ++i) {
      const PassInfo *Opt = OptimizationList[i];

      if (Opt->getNormalCtor())
        Passes.add(Opt->getNormalCtor()());
      else if (Opt->getTargetCtor()) {
#if 0
        if (target.get() == NULL)
          target.reset(allocateSparcTargetMachine()); // FIXME: target option
#endif
        assert(target.get() && "Could not allocate target machine!");
        Passes.add(Opt->getTargetCtor()(*target.get()));
      } else
        std::cerr << argv[0] << ": cannot create pass: " << Opt->getPassName()
                  << "\n";

      if (PrintEachXForm)
        Passes.add(new PrintModulePass(&std::cerr));
    }

    // Check that the module is well formed on completion of optimization
    if (!NoVerify)
      Passes.add(createVerifierPass());

    // Write bytecode out to disk or cout as the last step...
    if (!NoOutput)
      Passes.add(new WriteBytecodePass(Out, Out != &std::cout));

    // Now that we have all of the passes ready, run them.
    Passes.run(*M.get());

    return 0;

  } catch (const std::string& msg) {
    std::cerr << argv[0] << ": " << msg << "\n";
  } catch (...) {
    std::cerr << argv[0] << ": Unexpected unknown exception occurred.\n";
  }
  return 1;
}
<commit_msg>Fix a build failure<commit_after>//===- opt.cpp - The LLVM Modular Optimizer -------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Optimizations may be specified an arbitrary number of times on the command
// line, They are run in the order specified.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/Assembly/Parser.h"
#include "llvm/PassManager.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/PassNameParser.h"
#include "llvm/System/Signals.h"
#include "llvm/Support/PluginLoader.h"
#include "llvm/Support/SystemUtils.h"
#include "llvm/Support/Timer.h"
#include "llvm/Transforms/LinkAllPasses.h"
#include "llvm/LinkAllVMCore.h"
#include <fstream>
#include <memory>
#include <algorithm>

using namespace llvm;

// The OptimizationList is automatically populated with registered Passes by the
// PassNameParser.
//
static cl::list<const PassInfo*, bool,
                FilteredPassNameParser<PassInfo::Optimization> >
OptimizationList(cl::desc("Optimizations available:"));

// Other command line options...
//
static cl::opt<std::string>
InputFilename(cl::Positional, cl::desc("<input bytecode file>"),
    cl::init("-"), cl::value_desc("filename"));

static cl::opt<std::string>
OutputFilename("o", cl::desc("Override output filename"),
               cl::value_desc("filename"), cl::init("-"));

static cl::opt<bool>
Force("f", cl::desc("Overwrite output files"));

static cl::opt<bool>
PrintEachXForm("p", cl::desc("Print module after each transformation"));

static cl::opt<bool>
NoOutput("disable-output",
         cl::desc("Do not write result bytecode file"), cl::Hidden);

static cl::opt<bool>
NoVerify("disable-verify", cl::desc("Do not verify result module"), cl::Hidden);

static cl::opt<bool>
Quiet("q", cl::desc("Obsolete option"), cl::Hidden);

static cl::alias
QuietA("quiet", cl::desc("Alias for -q"), cl::aliasopt(Quiet));

static cl::opt<bool>
AnalyzeOnly("analyze", cl::desc("Only perform analysis, no optimization"));

// The AnalysesList is automatically populated with registered Passes by the
// PassNameParser.
static
  cl::list<const PassInfo*, bool, FilteredPassNameParser<PassInfo::Analysis> >
  AnalysesList(cl::desc("Analyses available:"));

static Timer BytecodeLoadTimer("Bytecode Loader");

// ---------- Define Printers for module and function passes ------------
namespace {

struct ModulePassPrinter : public ModulePass {
  const PassInfo *PassToPrint;
  ModulePassPrinter(const PassInfo *PI) : PassToPrint(PI) {}

  virtual bool runOnModule(Module &M) {
    if (!Quiet) {
      std::cout << "Printing analysis '" << PassToPrint->getPassName()
                << "':\n";
      getAnalysisID<Pass>(PassToPrint).print(std::cout, &M);
    }

    // Get and print pass...
    return false;
  }

  virtual const char *getPassName() const { return "'Pass' Printer"; }

  virtual void getAnalysisUsage(AnalysisUsage &AU) const {
    AU.addRequiredID(PassToPrint);
    AU.setPreservesAll();
  }
};

struct FunctionPassPrinter : public FunctionPass {
  const PassInfo *PassToPrint;
  FunctionPassPrinter(const PassInfo *PI) : PassToPrint(PI) {}

  virtual bool runOnFunction(Function &F) {
    if (!Quiet) {
      std::cout << "Printing analysis '" << PassToPrint->getPassName()
		<< "' for function '" << F.getName() << "':\n";
    }
    // Get and print pass...
    getAnalysisID<Pass>(PassToPrint).print(std::cout, F.getParent());
    return false;
  }

  virtual const char *getPassName() const { return "FunctionPass Printer"; }

  virtual void getAnalysisUsage(AnalysisUsage &AU) const {
    AU.addRequiredID(PassToPrint);
    AU.setPreservesAll();
  }
};

struct BasicBlockPassPrinter : public BasicBlockPass {
  const PassInfo *PassToPrint;
  BasicBlockPassPrinter(const PassInfo *PI) : PassToPrint(PI) {}

  virtual bool runOnBasicBlock(BasicBlock &BB) {
    if (!Quiet) {
      std::cout << "Printing Analysis info for BasicBlock '" << BB.getName()
		<< "': Pass " << PassToPrint->getPassName() << ":\n";
    }

    // Get and print pass...
    getAnalysisID<Pass>(PassToPrint).print(
      std::cout, BB.getParent()->getParent());
    return false;
  }

  virtual const char *getPassName() const { return "BasicBlockPass Printer"; }

  virtual void getAnalysisUsage(AnalysisUsage &AU) const {
    AU.addRequiredID(PassToPrint);
    AU.setPreservesAll();
  }
};

} // anonymous namespace

//===----------------------------------------------------------------------===//
// main for opt
//
int main(int argc, char **argv) {
  try {
    cl::ParseCommandLineOptions(argc, argv,
      " llvm .bc -> .bc modular optimizer and analysis printer \n");
    sys::PrintStackTraceOnErrorSignal();

    if (AnalyzeOnly) {
      Module *CurMod = 0;
#if 0
      TimeRegion RegionTimer(BytecodeLoadTimer);
#endif
      CurMod = ParseBytecodeFile(InputFilename);
      ParseError Err;
      if (!CurMod && !(CurMod = ParseAssemblyFile(InputFilename,&Err))){
        std::cerr << argv[0] << ": " << Err.getMessage() << "\n";
        return 1;
      }

      // Create a PassManager to hold and optimize the collection of passes we
      // are about to build...
      PassManager Passes;

      // Add an appropriate TargetData instance for this module...
      Passes.add(new TargetData(CurMod));

      // Make sure the input LLVM is well formed.
      if (!NoVerify)
        Passes.add(createVerifierPass());

      // Create a new optimization pass for each one specified on the
      // command line
      for (unsigned i = 0; i < AnalysesList.size(); ++i) {
        const PassInfo *Analysis = AnalysesList[i];

        if (Analysis->getNormalCtor()) {
          Pass *P = Analysis->getNormalCtor()();
          Passes.add(P);

          if (BasicBlockPass *BBP = dynamic_cast<BasicBlockPass*>(P))
            Passes.add(new BasicBlockPassPrinter(Analysis));
          else if (FunctionPass *FP = dynamic_cast<FunctionPass*>(P))
            Passes.add(new FunctionPassPrinter(Analysis));
          else
            Passes.add(new ModulePassPrinter(Analysis));

        } else
          std::cerr << argv[0] << ": cannot create pass: "
                    << Analysis->getPassName() << "\n";
      }

      Passes.run(*CurMod);

      delete CurMod;
      return 0;
    }

    // Allocate a full target machine description only if necessary...
    // FIXME: The choice of target should be controllable on the command line.
    std::auto_ptr<TargetMachine> target;

    TargetMachine* TM = NULL;
    std::string ErrorMessage;

    // Load the input module...
    std::auto_ptr<Module> M(ParseBytecodeFile(InputFilename, &ErrorMessage));
    if (M.get() == 0) {
      std::cerr << argv[0] << ": ";
      if (ErrorMessage.size())
        std::cerr << ErrorMessage << "\n";
      else
        std::cerr << "bytecode didn't read correctly.\n";
      return 1;
    }

    // Figure out what stream we are supposed to write to...
    // FIXME: cout is not binary!
    std::ostream *Out = &std::cout;  // Default to printing to stdout...
    if (OutputFilename != "-") {
      if (!Force && std::ifstream(OutputFilename.c_str())) {
        // If force is not specified, make sure not to overwrite a file!
        std::cerr << argv[0] << ": error opening '" << OutputFilename
                  << "': file exists!\n"
                  << "Use -f command line argument to force output\n";
        return 1;
      }
      std::ios::openmode io_mode = std::ios::out | std::ios::trunc |
                                   std::ios::binary;
      Out = new std::ofstream(OutputFilename.c_str(), io_mode);

      if (!Out->good()) {
        std::cerr << argv[0] << ": error opening " << OutputFilename << "!\n";
        return 1;
      }

      // Make sure that the Output file gets unlinked from the disk if we get a
      // SIGINT
      sys::RemoveFileOnSignal(sys::Path(OutputFilename));
    }

    // If the output is set to be emitted to standard out, and standard out is a
    // console, print out a warning message and refuse to do it.  We don't
    // impress anyone by spewing tons of binary goo to a terminal.
    if (!Force && !NoOutput && CheckBytecodeOutputToConsole(Out,!Quiet)) {
      NoOutput = true;
    }

    // Create a PassManager to hold and optimize the collection of passes we are
    // about to build...
    //
    PassManager Passes;

    // Add an appropriate TargetData instance for this module...
    Passes.add(new TargetData(M.get()));

    // Create a new optimization pass for each one specified on the command line
    for (unsigned i = 0; i < OptimizationList.size(); ++i) {
      const PassInfo *Opt = OptimizationList[i];

      if (Opt->getNormalCtor())
        Passes.add(Opt->getNormalCtor()());
      else if (Opt->getTargetCtor()) {
#if 0
        if (target.get() == NULL)
          target.reset(allocateSparcTargetMachine()); // FIXME: target option
#endif
        assert(target.get() && "Could not allocate target machine!");
        Passes.add(Opt->getTargetCtor()(*target.get()));
      } else
        std::cerr << argv[0] << ": cannot create pass: " << Opt->getPassName()
                  << "\n";

      if (PrintEachXForm)
        Passes.add(new PrintModulePass(&std::cerr));
    }

    // Check that the module is well formed on completion of optimization
    if (!NoVerify)
      Passes.add(createVerifierPass());

    // Write bytecode out to disk or cout as the last step...
    if (!NoOutput)
      Passes.add(new WriteBytecodePass(Out, Out != &std::cout));

    // Now that we have all of the passes ready, run them.
    Passes.run(*M.get());

    return 0;

  } catch (const std::string& msg) {
    std::cerr << argv[0] << ": " << msg << "\n";
  } catch (...) {
    std::cerr << argv[0] << ": Unexpected unknown exception occurred.\n";
  }
  return 1;
}
<|endoftext|>


<commit_before>/*
 * Logger.cpp
 *
 *  Created on: Jan 7, 2015
 *      Author: mda
 */

#include "Logger.h"
#include "Timer.h"
#include <iostream>
#include <fstream>
#include <qdir.h>
#include "util/Util.h"

bool Logger::writeToConsole = true;
bool Logger::writeToFile = false;
std::ofstream Logger::logFile;
Timer* Logger::timer = NULL;
Logger::Level Logger::level = Logger::Level::DEBUG;

Logger::Logger(std::string className) {
    this->className = className;
}

void Logger::setLoggingLevel(Level level) {
    Logger::level = level;
}

bool Logger::initialize(Level level, bool writeToConsole, bool writeToFile, Timer* timer) {
    Logger::level = level;
    Logger::writeToConsole = writeToConsole;
	Logger::writeToFile = writeToFile;
	Logger::timer = timer;

	if (writeToFile) {
		char buffer[80];
		strftime(buffer, 80, "%d-%m-%Y_%I:%M:%S.log", timer->getCurrentTime());

		std::string logName(buffer);

        //Create a logs folder if one does not exist and places a log file into
        QString test= QString::fromStdString(Util::getWorkingDirectory());
        QDir dir(test);

        if (!(QDir(QString::fromStdString(Util::getWorkingDirectory()+"/logs")).exists())) {
            dir.mkpath("logs");
        }

        logName = Util::getWorkingDirectory() + "/logs/"+ logName;

		logFile.open(logName.c_str());
		if (!logFile.is_open()) {
			std::cout << "Unable to create log file." << std::endl;
            return false;
		}
	}

	return true;

}

void Logger::trace(std::string msg) {
    if (Level::TRACE >= Logger::level) {
        char buffer[100];
        std::string output = "%d-%m-%Y %I:%M:%S\t" + className + "\tTRACE\t";
        strftime(buffer, 100, output.c_str(), timer->getCurrentTime());

        std::string finalMsg(buffer);
        finalMsg += msg;
        log(finalMsg);
    }
}

void Logger::info(std::string msg) {
    if (Level::INFO >= Logger::level) {
        char buffer[100];
        std::string output = "%d-%m-%Y %I:%M:%S\t" + className + "\tINFO\t";
        strftime(buffer, 100, output.c_str(), timer->getCurrentTime());

        std::string finalMsg(buffer);
        finalMsg += msg;
        log(finalMsg);
    }
}

void Logger::debug(std::string msg) {
    if (Level::DEBUG >= Logger::level) {
        char buffer[100];
        std::string output = "%d-%m-%Y %I:%M:%S\t" + className + "\tDEBUG\t";
        strftime(buffer, 100, output.c_str(), timer->getCurrentTime());

        std::string finalMsg(buffer);
        finalMsg += msg;
        log(finalMsg);
    }
}

void Logger::warn(std::string msg) {
    if (Level::WARN >= Logger::level) {
        char buffer[100];
        std::string output = "%d-%m-%Y %I:%M:%S\t" + className + "\tWARN\t";
        strftime(buffer, 100, output.c_str(), timer->getCurrentTime());

        std::string finalMsg(buffer);
        finalMsg += msg;
        log(finalMsg);
    }
}

void Logger::error(std::string msg) {
    if (Level::ERROR >= Logger::level) {
        char buffer[100];
        std::string output = "%d-%m-%Y %I:%M:%S\t" + className + "\tERROR\t";
        strftime(buffer, 100, output.c_str(), timer->getCurrentTime());

        std::string finalMsg(buffer);
        finalMsg += msg;
        log(finalMsg);
    }
}

void Logger::log(std::string msg) {
	if (writeToConsole) {
		std::cout << msg << std::endl;
	}

	if (writeToFile) {
		logFile << msg << std::endl;
	}
}

void Logger::close() {
	logFile.close();
	delete timer;
}

Logger::~Logger() {

}
<commit_msg>Changed log file name to start with time<commit_after>/*
 * Logger.cpp
 *
 *  Created on: Jan 7, 2015
 *      Author: mda
 */

#include "Logger.h"
#include "Timer.h"
#include <iostream>
#include <fstream>
#include <qdir.h>
#include "util/Util.h"

bool Logger::writeToConsole = true;
bool Logger::writeToFile = false;
std::ofstream Logger::logFile;
Timer* Logger::timer = NULL;
Logger::Level Logger::level = Logger::Level::DEBUG;

Logger::Logger(std::string className) {
    this->className = className;
}

void Logger::setLoggingLevel(Level level) {
    Logger::level = level;
}

bool Logger::initialize(Level level, bool writeToConsole, bool writeToFile, Timer* timer) {
    Logger::level = level;
    Logger::writeToConsole = writeToConsole;
	Logger::writeToFile = writeToFile;
	Logger::timer = timer;

	if (writeToFile) {
		char buffer[80];
        strftime(buffer, 80, "%I:%M:%S_%d-%m-%Y.log", timer->getCurrentTime());

		std::string logName(buffer);

        //Create a logs folder if one does not exist and places a log file into
        QString test= QString::fromStdString(Util::getWorkingDirectory());
        QDir dir(test);

        if (!(QDir(QString::fromStdString(Util::getWorkingDirectory()+"/logs")).exists())) {
            dir.mkpath("logs");
        }

        logName = Util::getWorkingDirectory() + "/logs/"+ logName;

		logFile.open(logName.c_str());
		if (!logFile.is_open()) {
			std::cout << "Unable to create log file." << std::endl;
            return false;
		}
	}

	return true;

}

void Logger::trace(std::string msg) {
    if (Level::TRACE >= Logger::level) {
        char buffer[100];
        std::string output = "%d-%m-%Y %I:%M:%S\t" + className + "\tTRACE\t";
        strftime(buffer, 100, output.c_str(), timer->getCurrentTime());

        std::string finalMsg(buffer);
        finalMsg += msg;
        log(finalMsg);
    }
}

void Logger::info(std::string msg) {
    if (Level::INFO >= Logger::level) {
        char buffer[100];
        std::string output = "%d-%m-%Y %I:%M:%S\t" + className + "\tINFO\t";
        strftime(buffer, 100, output.c_str(), timer->getCurrentTime());

        std::string finalMsg(buffer);
        finalMsg += msg;
        log(finalMsg);
    }
}

void Logger::debug(std::string msg) {
    if (Level::DEBUG >= Logger::level) {
        char buffer[100];
        std::string output = "%d-%m-%Y %I:%M:%S\t" + className + "\tDEBUG\t";
        strftime(buffer, 100, output.c_str(), timer->getCurrentTime());

        std::string finalMsg(buffer);
        finalMsg += msg;
        log(finalMsg);
    }
}

void Logger::warn(std::string msg) {
    if (Level::WARN >= Logger::level) {
        char buffer[100];
        std::string output = "%d-%m-%Y %I:%M:%S\t" + className + "\tWARN\t";
        strftime(buffer, 100, output.c_str(), timer->getCurrentTime());

        std::string finalMsg(buffer);
        finalMsg += msg;
        log(finalMsg);
    }
}

void Logger::error(std::string msg) {
    if (Level::ERROR >= Logger::level) {
        char buffer[100];
        std::string output = "%d-%m-%Y %I:%M:%S\t" + className + "\tERROR\t";
        strftime(buffer, 100, output.c_str(), timer->getCurrentTime());

        std::string finalMsg(buffer);
        finalMsg += msg;
        log(finalMsg);
    }
}

void Logger::log(std::string msg) {
	if (writeToConsole) {
		std::cout << msg << std::endl;
	}

	if (writeToFile) {
		logFile << msg << std::endl;
	}
}

void Logger::close() {
	logFile.close();
	delete timer;
}

Logger::~Logger() {

}
<|endoftext|>