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

#include "cnf_manager.hpp"

#include <boost/format.hpp>

#include <core/utils/bitset_utils.hpp>
#include <core/utils/timer.hpp>
#include <classical/functions/isop.hpp>

namespace cirkit
{

/******************************************************************************
 * Types                                                                      *
 ******************************************************************************/

/******************************************************************************
 * Private functions                                                          *
 ******************************************************************************/

/******************************************************************************
 * Public functions                                                           *
 ******************************************************************************/

cnf_manager::vertex_range_t cnf_manager::compute( const tt& func, unsigned* literal_count )
{
  const auto key = to_string( func );
  const auto it = hash.find( key );

  unsigned begin = 0u, end = 0u, count = 0u;

  if ( it != hash.end() )
  {
    ++cache_hit;
    begin = std::get<0>( it->second );
    end   = std::get<1>( it->second );
    count = std::get<2>( it->second );
  }
  else
  {
    ++cache_miss;
    increment_timer t( &runtime );
    begin = covers.size();
    tt_cnf( func, covers );
    end = covers.size();

    /* count literals */
    const auto num_vars = tt_num_vars( func );
    for ( auto i = begin; i < end; ++i )
    {
      for ( auto x = 0u; x < num_vars; ++x )
      {
        if ( ( covers[i] >> ( x << 1 ) ) & 3 )
        {
          ++count;
        }
      }
    }

    hash[key] = std::make_tuple( begin, end, count );
  }

  if ( literal_count )
  {
    *literal_count = count;
  }

  return boost::make_iterator_range( covers.begin() + begin, covers.begin() + end );
}

void cnf_manager::print_statistics( std::ostream& os ) const
{
  os << boost::format( "[i] CNF manager: size = %d   cache hits = %d   cache misses = %d   run-time = %.2f secs" ) % hash.size() % cache_hit % cache_miss % runtime << std::endl;
}

}

// Local Variables:
// c-basic-offset: 2
// eval: (c-set-offset 'substatement-open 0)
// eval: (c-set-offset 'innamespace 0)
// End:

max_stars_repo_name: eletesta/cirkit

max_issues_repo_name: eletesta/cirkit

max_forks_repo_name: eletesta/cirkit


text:
/* Copyright (c) 2020 UATC, LLC

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

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

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

#include "neuropod/multiprocess/shm/shm_allocator.hh"

#include "fmt/ranges.h"
#include "neuropod/internal/error_utils.hh"
#include "neuropod/internal/memory_utils.hh"

#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>

#include <list>
#include <mutex>
#include <unordered_map>

namespace neuropod
{

namespace
{

namespace ipc = boost::interprocess;

// A struct stored in shared memory that contains the data and a cross process refcount
struct __attribute__((__packed__)) SHMBlockInternal
{
    // This mutex is used to synchronize operations on the metadata below
    ipc::interprocess_mutex mutex;

    // The number of times this block is used across processes
    size_t refcount = 0;

    // These blocks of memory can be reused
    // This is incremented on each reuse to invalidate stale blocks
    uint64_t reuse_count = 0;

    // The data in this block
    uint8_t data[];

    // Delete the copy and move constructors
    // (if the copy constructors are deleted, no move constructors will be autogenerated)
    SHMBlockInternal()                         = default;
    ~SHMBlockInternal()                        = default;
    SHMBlockInternal(const SHMBlockInternal &) = delete;
    SHMBlockInternal &operator=(const SHMBlockInternal &) = delete;
};

// A unique ID for a SHM block
// Since blocks of memory can be reused, the UUID used to load
// the block isn't enough. An additional `reuse_count` field is
// used to detect when stale IDs are used and throw an error.
struct __attribute__((__packed__)) SHMBlockIDInternal
{
    RawSHMHandle block_handle;
    uint64_t     reuse_count = 0;
};

// Make sure the size of the ID struct matches the size of the user facing version
static_assert(sizeof(SHMBlockIDInternal) == std::tuple_size<SHMBlockID>::value,
              "The size of SHMBlockIDInternal must match the size of SHMBlockID");

} // namespace

// A cache for raw blocks we've loaded before
class LoadCache
{
private:
    std::map<RawSHMHandle, std::shared_ptr<void>> loaded_cache_;
    std::mutex                                    loaded_cache_mutex_;

public:
    LoadCache()  = default;
    ~LoadCache() = default;

    // Try to get a raw block from the loaded cache
    // If this returns a block, it removes it from the cache
    void maybe_get_and_pop(const RawSHMHandle &handle, std::shared_ptr<void> &raw_block)
    {
        std::lock_guard<std::mutex> lock(loaded_cache_mutex_);
        auto                        item = loaded_cache_.find(handle);
        if (item != loaded_cache_.end())
        {
            raw_block = item->second;
            loaded_cache_.erase(item);
        }
    }

    void insert(RawSHMHandle handle, std::shared_ptr<void> item)
    {
        std::lock_guard<std::mutex> lock(loaded_cache_mutex_);
        loaded_cache_[handle] = std::move(item);
    }

    void clear()
    {
        std::lock_guard<std::mutex> lock(loaded_cache_mutex_);
        loaded_cache_.clear();
    }
};

// A cache for raw blocks we've created
class AllocationCache
{
private:
    // A struct that wraps a raw block and its handle
    struct RawBlockWrapper
    {
        std::shared_ptr<void> block;
        RawSHMHandle          block_handle;
    };

    // In our cache, the main operations we care about are the following:
    //  - equal_range (give me all raw blocks of a certain size)
    //  - erase       (remove a specific raw block from the cache)
    //  - insert      (add a raw block of a specific size to the cache)
    //
    // By using an unordered_map with a list, all the operations we care about can be implemented
    // in an O(1) way. This is better than using an `std::unordered_multimap` or a `std::multimap`
    // directly
    //
    // More importantly, using this structure has a significant improvement on benchmarks over
    // using a multimap or an unordered_multimap
    std::unordered_map<size_t, std::list<RawBlockWrapper>> created_cache_;
    std::mutex                                             created_cache_mutex_;

public:
    AllocationCache()  = default;
    ~AllocationCache() = default;

    // Maybe get an unused raw block from the created cache
    // Increments the refcount and reuse count of the returned block (if any)
    // If this returns a block, it removes it from the cache
    void maybe_get_and_pop(size_t requested_size, std::shared_ptr<void> &raw_block, SHMBlockIDInternal &id)
    {
        std::lock_guard<std::mutex> lock(created_cache_mutex_);
        auto &                      range = created_cache_[requested_size];
        for (auto it = range.begin(); it != range.end(); it++)
        {
            auto &cache_item   = *it;
            auto *cached_block = static_cast<SHMBlockInternal *>(cache_item.block.get());

            ipc::scoped_lock<ipc::interprocess_mutex> lock(cached_block->mutex);

            // Check whether or not this block is used in another process
            if (cached_block->refcount == 0)
            {
                // The block is unused so we can use it!
                // Increment the refcount
                cached_block->refcount++;

                // Increase the reuse_count so that stale IDs will no longer work
                cached_block->reuse_count++;

                raw_block       = cache_item.block;
                id.reuse_count  = cached_block->reuse_count;
                id.block_handle = cache_item.block_handle;

                range.erase(it);
                return;
            }
        }
    }

    void insert(size_t size_bytes, RawSHMHandle handle, std::shared_ptr<void> item)
    {
        std::lock_guard<std::mutex> lock(created_cache_mutex_);
        RawBlockWrapper             wrapper = {std::move(item), handle};
        created_cache_[size_bytes].emplace_back(std::move(wrapper));
    }

    void clear()
    {
        std::lock_guard<std::mutex> lock(created_cache_mutex_);
        created_cache_.clear();
    }
};

SHMAllocator::SHMAllocator()
    : allocation_cache_(stdx::make_unique<AllocationCache>()), load_cache_(stdx::make_unique<LoadCache>())
{
}

SHMAllocator::~SHMAllocator() = default;

std::shared_ptr<void> SHMAllocator::allocate_shm(size_t size_bytes, SHMBlockID &block_id)
{
    // The id to return to the caller
    SHMBlockIDInternal id;

    // The underlying raw block
    std::shared_ptr<void> raw_block;

    // Include the size of our metadata
    auto requested_size = size_bytes + sizeof(SHMBlockInternal);

    // Maybe get a raw block of the requested size from the cache
    allocation_cache_->maybe_get_and_pop(requested_size, raw_block, id);

    // If we didn't get anything from the cache
    if (raw_block == nullptr)
    {
        // Create a block of the requested size
        raw_block = allocator_.allocate_shm(requested_size, id.block_handle);

        // Get a pointer to the struct and initialize it
        auto *block = new (raw_block.get()) SHMBlockInternal;

        // Increment the refcount
        block->refcount++;
    }

    // Return the ID of this block to the caller
    memcpy(block_id.data(), &id, sizeof(id));

    // Get the block from the raw block
    auto *block = static_cast<SHMBlockInternal *>(raw_block.get());

    // Create a shared pointer to the underlying data with a custom deleter
    // that keeps the block alive. Add the block to the cache on destruction.
    return std::shared_ptr<void>(
        block->data, [this, block, raw_block = std::move(raw_block), requested_size, id](void *unused) mutable {
            {
                // Lock the block's mutex
                ipc::scoped_lock<ipc::interprocess_mutex> lock(block->mutex);

                // Decrement the refcount
                block->refcount--;
            }

            // Add it to the created cache
            allocation_cache_->insert(requested_size, id.block_handle, std::move(raw_block));
        });
}

std::shared_ptr<void> SHMAllocator::load_shm(const SHMBlockID &block_id)
{
    // Load an existing block of shared memory by ID
    auto id     = reinterpret_cast<const SHMBlockIDInternal *>(block_id.data());
    auto handle = id->block_handle;

    // The underlying raw block
    std::shared_ptr<void> raw_block;

    // Check if we can get it from the cache
    load_cache_->maybe_get_and_pop(handle, raw_block);

    // If not, load it from scratch
    if (raw_block == nullptr)
    {
        raw_block = allocator_.load_shm(handle);
    }

    // Get the block from the raw block
    auto *block = static_cast<SHMBlockInternal *>(raw_block.get());

    // Sanity checks to avoid race conditions + increment the refcount
    {
        // Lock the block's mutex
        ipc::scoped_lock<ipc::interprocess_mutex> lock(block->mutex);

        // Sanity check
        if (block->refcount == 0)
        {
            // This means that the other process isn't keeping references to data long enough for this
            // process to load the data.
            // This can lead to some hard to debug race conditions so we always throw an error.
            NEUROPOD_ERROR("Tried getting a pointer to an existing chunk of memory that has a refcount of zero: {}",
                           handle);
        }

        // Make sure the `reuse_count` matches what we expect
        if (id->reuse_count != block->reuse_count)
        {
            // This means that the other process isn't keeping references to data long enough for this
            // process to load the data.
            // (A block of memory went out of scope and was reused before it could be loaded by the other process)
            NEUROPOD_ERROR("Tried loading a block of memory that went out of scope in the creating process. "
                           "Ensure that blocks of SHM stay in scope until they are loaded by the receiving process. "
                           "UUID: {}. Reuse count: {}. Expected reuse count: {}",
                           handle,
                           block->reuse_count,
                           id->reuse_count);
        }

        // Increment the refcount
        block->refcount++;
    }

    // Create a shared pointer to the underlying data with a custom deleter
    // that keeps the block alive. Add the block to the cache on destruction.
    return std::shared_ptr<void>(block->data,
                                 [this, block, raw_block = std::move(raw_block), handle](void *unused) mutable {
                                     {
                                         // Lock the block's mutex
                                         ipc::scoped_lock<ipc::interprocess_mutex> lock(block->mutex);

                                         // Decrement the refcount
                                         block->refcount--;
                                     }

                                     // Add it to the load cache
                                     load_cache_->insert(handle, std::move(raw_block));
                                 });
}

void SHMAllocator::free_unused_shm_blocks()
{
    // Free all currently unused blocks in the caches
    allocation_cache_->clear();
    load_cache_->clear();
}

// A shared memory allocator that is used by the WireFormat and by SHMNeuropodTensor
// TODO(vip): Remove global allocator instance
SHMAllocator shm_allocator;

} // namespace neuropod

ext: cc

max_stars_repo_name: qiyanz/neuropod

max_issues_repo_name: qiyanz/neuropod

max_forks_repo_name: qiyanz/neuropod


text:
/** @file 38.cpp Problem 38: Pandigital multiples
 *
 * Take the number 192 and multiply it by each of 1, 2, and 3:
 *
 *      192 x 1 = 192
 *      192 x 2 = 384
 *      192 x 3 = 576
 *
 * By concatenating each product we get the 1 to 9 pandigital, 192384576. We
 * will call 192384576 the concatenated product of 192 and (1,2,3)
 *
 * The same can be achieved by starting with 9 and multiplying by 1, 2, 3, 4,
 * and 5, giving the pandigital, 918273645, which is the concatenated product
 * of 9 and (1,2,3,4,5).
 *
 * What is the largest 1 to 9 pandigital 9-digit number that can be formed as
 * the concatenated product of an integer with (1,2, ... , n) where n > 1?
 */

// At most eight values of n, 2 through 9, are worth considering; n < 2 is
// explicitly prohibited by the problem description, and n > 9 will produce a
// number that exceeds the specified (9-digit) length.
//
// Similarly, we can limit the values of the multiplicand `m` to those that
// produce 9-digit concatenated products.

#include "int_util.hpp"                         // pandigital

/// @cond
#include <boost/iterator/counting_iterator.hpp> // counting_iterator
#include <boost/multiprecision/cpp_int.hpp>     // cpp_int

#include <algorithm>                            // all_of
#include <iostream>                             // cout
#include <vector>
/// @endcond

using boost::make_counting_iterator;
using boost::multiprecision::cpp_int;
using int_util::length;
using int_util::pandigital;

cpp_int cat_prod(cpp_int const& m, std::vector<int> const& v)
{
    std::string s;
    for (auto const& x : v)
        s += cpp_int(m * x).str();
    return cpp_int(s);
}

int main()
{
    cpp_int r = 0;
    for (int n = 2; n <= 9; ++n) {
        std::vector<int> v(
                make_counting_iterator(1),
                make_counting_iterator(n + 1));
        cpp_int m = 1;
        auto p = cat_prod(m, v);
        while (p.str().size() < 9) {  // Skip products that are too short.
            ++m;
            p = cat_prod(m, v);
        }
        while (p.str().size() == 9) {
            if (p > r && pandigital(p))
                r = p;
            p = cat_prod(++m, v);
        }
    }
    std::cout << r << std::endl;
}

ext: cpp

max_stars_repo_name: jeffs/cpp-euler

max_issues_repo_name: jeffs/cpp-euler

max_forks_repo_name: jeffs/cpp-euler


text:
#pragma once

// Bib
#include "arguments.hpp"

// Boost
#include <boost/program_options.hpp>

// STL
#include <string>
#include <vector>

namespace bib {
    namespace front_end {
        /**
         * @brief Shorter namespace alias for program options management.
         */
        namespace po = boost::program_options;

        /**
         * @brief The parser is responsible for deserializing the command
         * line arguments.
         */
        class parser final {
        public:
            /**
             * @brief Constructor.
             * It starts parsing the action of subject.
             */
            explicit parser(int argc, char** argv);

            /**
             * @brief Get the parsed action.
             * @return the action.
             */
            action_t get_action() const noexcept { return action; }

            /**
             * @brief Get the parsed subject.
             * @return the subject.
             */
            subject_t get_subject() const noexcept { return subject; }

            /**
             * @brief Get the help message.
             * @return the help message.
             */
            std::string get_help() const;

            /**
             * @brief Parse the remaining specific arguments.
             * These arguments depend on the selected action and subject.
             * This method is meant to be specialized.
             * @return the strongly-typed argument from the selected
             * action and subject, and remaining arguments.
             */
            template <typename TArgument>
            TArgument parse();

        private:
            void parse_action_and_subject();

            [[nodiscard]] po::options_description get_global_options() const;
            [[nodiscard]] po::options_description get_author_addition_options() const;
            [[nodiscard]] po::options_description get_author_search_options() const;
            [[nodiscard]] po::options_description get_book_addition_options() const;
            [[nodiscard]] po::options_description get_book_search_options() const;
            void collect_extra_arguments(const po::options_description& options);

            int argc;
            char** argv;
            action_t action;
            subject_t subject;
            po::variables_map variables;
            po::parsed_options parsed_options;
        };

        /**
         * @brief Author addition argument parser.
         */
        template <>
        inline arguments::author_addition_arg parser::parse<arguments::author_addition_arg>()
        {
            const auto options = get_author_addition_options();
            collect_extra_arguments(options);

            return {
                variables["email"].as<std::string>(),
                (variables.count("first-name")) ? variables["first-name"].as<std::string>() : "",
                (variables.count("last-name")) ? variables["last-name"].as<std::string>() : "",
                (variables.count("mobile")) ? variables["mobile"].as<std::string>() : "",
                (variables.count("address")) ? variables["address"].as<std::string>() : "",
                (variables.count("city")) ? variables["city"].as<std::string>() : "",
                (variables.count("birth-date")) ? variables["birth-date"].as<std::string>() : ""
            };
        }

        /**
         * @brief Author search argument parser.
         */
        template <>
        inline arguments::author_search_arg parser::parse<arguments::author_search_arg>()
        {
            const auto options = get_author_search_options();
            collect_extra_arguments(options);

            return {
                variables["book"].as<std::string>()
            };
        }

        /**
         * @brief Book addition argument parser.
         */
        template <>
        inline arguments::book_addition_arg parser::parse<arguments::book_addition_arg>()
        {
            const auto options = get_book_addition_options();
            collect_extra_arguments(options);

            return {
                variables["isbn"].as<std::string>(),
                variables["title"].as<std::string>(),
                variables["year"].as<std::string>(),
                variables["authors"].as<std::vector<std::string>>()
            };
        }

        /**
         * @brief Book search argument parser.
         */
        template <>
        inline arguments::book_search_arg parser::parse<arguments::book_search_arg>()
        {
            const auto options = get_book_search_options();
            collect_extra_arguments(options);

            arguments::book_search_arg arg;
            if (variables.count("email")) {
                arg.author_email = variables["email"].as<std::string>();
            }
            if (variables.count("last-name")) {
                arg.author_last_name = variables["last-name"].as<std::string>();
            }

            return arg;
        }
    }
}

ext: hpp

max_stars_repo_name: loic-yvonnet/bib

max_issues_repo_name: loic-yvonnet/bib

max_forks_repo_name: loic-yvonnet/bib


text:
//
// Created by qfeng on 2018-12-30.
//

#include "pipeline/pipeline.h"
#include <boost/thread/latch.hpp>

namespace algocomp {
    const std::vector<std::string> Pipeline::head_to_middle(const char *attrs_pb, long len_attrs_pb) {
        std::vector<std::string> outp;
        google::protobuf::Arena arena;

        try {
            auto feats_ = _head->work(attrs_pb, len_attrs_pb, arena);

            if (feats_.has_value()) {
                auto feats = feats_.value();
                outp = _middle->work_toenc(feats, arena);
            } else {
                _logger->error("Transform attribute data fail in head->work.");
            }

        } catch (const exception &ex) {
            _logger->error("Transform data fail in head_to_middle fail: {}", ex.what());
        }

        if (arena.SpaceAllocated()) arena.Reset();
        return outp;
    }

    std::vector<float> Pipeline::middle_to_tail(const char *feats_pb, long len_feats_pb) {
        vector<float> outp;
        google::protobuf::Arena arena;

        try {
            AUCImprFeats *feats = google::protobuf::Arena::CreateMessage<AUCImprFeats>(&arena);
            feats->ParseFromArray(feats_pb, len_feats_pb);
            auto encoded = _middle->work_tokv(*feats, arena);

            if (encoded.has_value()) {
                outp = _tail->work(encoded.value());
            } else {
                _logger->error("Transform feature data fail in middle_to_tail.");
            }
        } catch (const exception &ex) {
            _logger->error("Transform data fail in middle_to_tail fail: {}", ex.what());
        }

        if (arena.SpaceAllocated()) arena.Reset();
        return outp;

    }

    std::vector<float> Pipeline::head_to_tail(const char *attrs_pb, long len_attrs_pb) {
        vector<float> outp;
        google::protobuf::Arena arena;

        try {
            auto feats_ = _head->work(attrs_pb, len_attrs_pb, arena);
            if (feats_.has_value()) {
                auto feats = feats_.value();
                auto encoded = _middle->work_tokv(feats, arena);

                if (encoded.has_value()) {
                    outp = _tail->work(encoded.value());
                } else {
                    _logger->error("Transform feature data fail in head_to_tail.");
                }
            } else {
                _logger->error("Transform attribute data fail in head_to_tail.");
            }

        } catch (const exception &ex) {
            _logger->error("Transform data fail in head_to_tail: {}.", ex.what());
        }

        if (arena.SpaceAllocated()) arena.Reset();
        return outp;
    }

    bool Pipeline::save_name2enc(const string &fname) {
        if (_middle) {
            _middle->save_name2enc(fname);
        } else {
            _logger->error("Save name2enc in with empty pipeline middle.");
        }
    }
}


text:
/*=============================================================================
    Copyright (c) 2005-2007 Dan Marsden
    Copyright (c) 2005-2007 Joel de Guzman

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
==============================================================================*/

#include <boost/phoenix/core.hpp>
#include <boost/phoenix/stl/algorithm/iteration.hpp>
#include <boost/detail/lightweight_test.hpp>

#include <functional>

namespace
{
    struct for_each_tester
    {
        int value_;
        for_each_tester() : value_(0) { }
        void operator()(
            int& i)
        {
            value_ += i++;
            return;
        }
    };

    void for_each_test()
    {
        using boost::phoenix::for_each;
        using boost::phoenix::arg_names::arg1;
        int array[] = {1,2,3};
        BOOST_TEST(for_each(arg1, for_each_tester())(array).value_ == 6);
        BOOST_TEST(array[0] == 2);
        BOOST_TEST(array[1] == 3);
        BOOST_TEST(array[2] == 4);
        return;
    }

    void accumulate_test()
    {
        using boost::phoenix::accumulate;
        using boost::phoenix::arg_names::arg1;
        int array[] = {1,2,3};
        BOOST_TEST(accumulate(arg1, 0)(array) == 6);
        BOOST_TEST(boost::phoenix::accumulate(arg1, 0, std::minus<int>())(array) == -6);
        return;
    }
}

int main()
{
    for_each_test();
    accumulate_test();
    boost::report_errors();
}

max_stars_repo_name: randolphwong/mcsema

max_issues_repo_name: randolphwong/mcsema

max_forks_repo_name: randolphwong/mcsema


text:
// -----------------------------------------------------------------------------
// Fern © Geoneric
//
// This file is part of Geoneric Fern which is available under the terms of
// the GNU General Public License (GPL), version 2. If you do not want to
// be bound by the terms of the GPL, you may purchase a proprietary license
// from Geoneric (http://www.geoneric.eu/contact).
// -----------------------------------------------------------------------------
#define BOOST_TEST_MODULE fern algorithm convolution neighborhood square
#include <boost/test/unit_test.hpp>
#include "fern/core/data_customization_point/scalar.h"
#include "fern/algorithm/convolution/neighborhood/square_traits.h"
#include "fern/algorithm/algebra/elementary/multiply.h"

namespace fa = fern::algorithm;

BOOST_AUTO_TEST_CASE(square)
{
    {
        fern::Square<int, 1> square({
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9}
        });

        BOOST_CHECK_EQUAL(square.weight(0), 1);
        BOOST_CHECK_EQUAL(square.weight(4), 5);
        BOOST_CHECK_EQUAL(square.weight(8), 9);
    }
}

BOOST_AUTO_TEST_CASE(verify_use_in_algorithm)
{
    // Verify we can pass a square to an operation.

    fa::SequentialExecutionPolicy sequential;

    // Multiply.
    {
        fern::Square<int, 1> square({
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9}
        });

        fa::algebra::multiply(sequential, square, 2, square);

        BOOST_CHECK_EQUAL(square.weight(0), 2);
        BOOST_CHECK_EQUAL(square.weight(1), 4);
        BOOST_CHECK_EQUAL(square.weight(2), 6);
        BOOST_CHECK_EQUAL(square.weight(3), 8);
        BOOST_CHECK_EQUAL(square.weight(4), 10);
        BOOST_CHECK_EQUAL(square.weight(5), 12);
        BOOST_CHECK_EQUAL(square.weight(6), 14);
        BOOST_CHECK_EQUAL(square.weight(7), 16);
        BOOST_CHECK_EQUAL(square.weight(8), 18);
    }
}

max_stars_repo_name: quanpands/wflow

max_issues_repo_name: quanpands/wflow

max_forks_repo_name: quanpands/wflow


text:
/*    Copyright (c) 2010-2015, Delft University of Technology
 *    All rights reserved.
 *
 *    Redistribution and use in source and binary forms, with or without modification, are
 *    permitted provided that the following conditions are met:
 *      - Redistributions of source code must retain the above copyright notice, this list of
 *        conditions and the following disclaimer.
 *      - Redistributions in binary form must reproduce the above copyright notice, this list of
 *        conditions and the following disclaimer in the documentation and/or other materials
 *        provided with the distribution.
 *      - Neither the name of the Delft University of Technology 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 THE
 *    COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 *    GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 *    AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 *    OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *    Changelog
 *      YYMMDD    Author            Comment
 *      110621    F.M. Engelen      File created.
 *      110707    E.A.G. Heeren     Minor spelling/lay-out corrections.
 *      110714    E.A.G. Heeren     Minor spelling/lay-out corrections.
 *      110905    S. Billemont      Reorganized includes.
 *                                  Moved (con/de)structors and getter/setters to header.
 *      120529    E.A.G. Heeren     Boostified unit test.
 *      120615    T. Secretin       Added check for exception handling.
 *      120716    D. Dirkx          Updated with interpolator architecture.
 *
 *    References
 *
 *    Notes
 *
 */

#define BOOST_TEST_MAIN

#include <boost/test/unit_test.hpp>

#include <vector>

#include "Tudat/Basics/testMacros.h"
#include "Tudat/InputOutput/matrixTextFileReader.h"

#include "Tudat/Mathematics/Interpolators/cubicSplineInterpolator.h"
#include "Tudat/InputOutput/basicInputOutput.h"

namespace tudat
{
namespace unit_tests
{

// NOTE: No benchmark data from established software package has been used. Matlab implementation
// is slightly different than that implemented here, yielding error of at worst 10e-7 compared
// when using error function, which is used here as test function.
// However, a Matlab implementation of the same algorithm was found on te Matlab forum,
// which is used here as benchmark.
// In addition, the code has been used rather extensively and has been checked for basic
// characteristics such as continuity.
BOOST_AUTO_TEST_SUITE( test_cubic_spline_interpolator )

// Test implementation of cubic spline class.
BOOST_AUTO_TEST_CASE( testCubicSplineInterpolator )
{
    // Test 1: Compare with analytical function 2 + 3x + 5x^2.
    {
        // Declare and initialize independent variable values.
        std::vector< double > independentVariables;
        independentVariables.resize( 6 );
        independentVariables[ 0 ] = 1.0;
        independentVariables[ 1 ] = 3.0;
        independentVariables[ 2 ] = 5.0;
        independentVariables[ 3 ] = 7.0;
        independentVariables[ 4 ] = 9.0;
        independentVariables[ 5 ] = 11.0;

        // Declare and initialize dependent variable values.
        std::vector< double > dependentVariables;
        dependentVariables.resize( 6 );
        dependentVariables[ 0 ] = 10.0;
        dependentVariables[ 1 ] = 56.0;
        dependentVariables[ 2 ] = 142.0;
        dependentVariables[ 3 ] = 268.0;
        dependentVariables[ 4 ] = 434.0;
        dependentVariables[ 5 ] = 640.0;

        // Declare and initialize target independent variable value.
        const double targetIndependentVariableValue = 6.0;

        // Declare and initialize expected result of interpolation from analytical equation.
        const double analyticalValue = 200.0;

        // Declare cubic spline object and initialize with input data.
        interpolators::CubicSplineInterpolatorDouble cubicSplineInterpolation(
                    independentVariables, dependentVariables );

        // Declare interpolated dependent variable value and execute interpolation.
        const double interpolatedDependentVariableValue = cubicSplineInterpolation.interpolate(
                    targetIndependentVariableValue );

        // Check if test result match analytical result.
        BOOST_CHECK_SMALL(  std::fabs( analyticalValue - interpolatedDependentVariableValue )
                            / analyticalValue,
                            5.0e-3 );
    }
}

// Test exception handling implementation of cubic spline class.
BOOST_AUTO_TEST_CASE( testCubicSplineInterpolation_exception_empty_vectors )
{
    // Test 2: Interpolate with empty vectors.
    // Declare independent and dependent variable vectors.
    std::vector< double > independentVariables, dependentVariables;

    // Declare and initialize flag.
    bool areDependentAndIndependentVariablesInitialized = true;

    // Try to initialize with empty vectors.
    try
    {
        // Declare cubic spline object and initialize with input data.
        interpolators::CubicSplineInterpolatorDouble cubicSplineInterpolation(
                    independentVariables, dependentVariables );
    }

    // Catch the expected runtime error, and set the boolean flag to false.
    catch ( std::runtime_error )
    {
        areDependentAndIndependentVariablesInitialized = false;
    }

    // Check value of flag.
    BOOST_CHECK( !areDependentAndIndependentVariablesInitialized );
}

// Test cubic spline interpolator by comparing to Matlab code posted at
// http://www.mathworks.com/matlabcentral/newsreader/view_thread/173708.
BOOST_AUTO_TEST_CASE( test_cubicSplineInterpolator_matlab_forum_compare )
{
    using namespace interpolators;

    // Load input data used for generating matlab interpolation.
    Eigen::MatrixXd inputData = input_output::readMatrixFromFile(
                input_output::getTudatRootPath( ) +
                "Mathematics/Interpolators/UnitTests/interpolator_test_input_data.dat","," );

    // Put data in STL vectors.
    std::vector< double > independentVariableValues;
    std::vector< double > dependentVariableValues;
    for ( int i = 0; i < inputData.rows( ); i++ )
    {
        independentVariableValues.push_back( inputData( i, 0 ) );
        dependentVariableValues.push_back( inputData( i, 1 ) );
    }

    // Create cubic spline interpolator using hunting algorithm.
    CubicSplineInterpolatorDouble cubicSplineInterpolator(
                independentVariableValues, dependentVariableValues, huntingAlgorithm );

    // Load points at which interpolator is to be evaluated and data generated by Matlab.
    Eigen::MatrixXd benchmarkData = input_output::readMatrixFromFile(
                input_output::getTudatRootPath( ) +
                "Mathematics/Interpolators/UnitTests/"
                + "cubic_spline_interpolator_test_output_data.dat",
                "," );

    // Perform interpolation for required data points.
    Eigen::VectorXd outputData = Eigen::VectorXd( benchmarkData.rows( ) );
    for ( int i = 0; i < outputData.rows( ); i++ )
    {
        outputData[ i ] = cubicSplineInterpolator.interpolate( benchmarkData( i, 0 ) );
    }

    TUDAT_CHECK_MATRIX_CLOSE_FRACTION( benchmarkData.block( 0, 1, benchmarkData.rows( ), 1 ),
                                       outputData, 1.0e-13 );

    // Create cubic spline interpolator, now using binary search algorithm.
    cubicSplineInterpolator = CubicSplineInterpolatorDouble(
                independentVariableValues, dependentVariableValues, huntingAlgorithm );

    // Perform interpolation for required data points.
    outputData = Eigen::VectorXd( benchmarkData.rows( ) );
    for ( int i = 0; i < outputData.rows( ); i++ )
    {
        outputData[ i ] = cubicSplineInterpolator.interpolate( benchmarkData( i, 0 ) );
    }

    TUDAT_CHECK_MATRIX_CLOSE_FRACTION( benchmarkData.block( 0, 1, benchmarkData.rows( ), 1 ),
                                       outputData, 1.0e-13 );
}

// Test cubic spline interpolator by comparing to Matlab implementation. Note that the two
// implementations are not identical, since the Matlab implementation imposes zero first
// derivatives whereas the present implementation imposes zero second derivatives at endpoints.
BOOST_AUTO_TEST_CASE( test_cubicSplineInterpolator_matlab_compare )
{
    using namespace interpolators;

    // Load input data used for generating matlab interpolation.
    Eigen::MatrixXd inputData = input_output::readMatrixFromFile(
                input_output::getTudatRootPath( ) +
                "Mathematics/Interpolators/UnitTests/interpolator_test_input_data.dat", "," );

    // Put data in STL vectors.
    std::vector< double > independentVariableValues;
    std::vector< double > dependentVariableValues;
    for ( int i = 0; i < inputData.rows( ); i++ )
    {
        independentVariableValues.push_back( inputData( i, 0 ) );
        dependentVariableValues.push_back( inputData( i, 1 ) );
    }

    // Create cubic spline interpolator.
    CubicSplineInterpolatorDouble linearInterpolator(
                independentVariableValues, dependentVariableValues );

    // Load points at which interpolator is to be evaluated and data generated by Matlab.
    Eigen::MatrixXd benchmarkData = input_output::readMatrixFromFile(
                input_output::getTudatRootPath( ) +
                "Mathematics/Interpolators/UnitTests/"
                + "cubic_spline_interpolator_approximate_test_output_data.dat", "," );

    // Perform interpolation for required data points.
    Eigen::VectorXd outputData = Eigen::VectorXd( benchmarkData.rows( ) );
    for ( int i = 0; i < outputData.rows( ); i++ )
    {
        outputData[ i ] = linearInterpolator.interpolate( benchmarkData( i, 0 ) );
    }

    TUDAT_CHECK_MATRIX_CLOSE_FRACTION( benchmarkData.block( 0, 1, benchmarkData.rows( ), 1 ),
                                       outputData, 1.0e-5 );
}

BOOST_AUTO_TEST_SUITE_END( )

} // namespace unit_tests
} // namespace tudat

max_stars_repo_name: JPelamatti/ThesisTUDAT

max_issues_repo_name: JPelamatti/ThesisTUDAT

max_forks_repo_name: JPelamatti/ThesisTUDAT


text:
/*=============================================================================
    Copyright (c) 2001-2007 Joel de Guzman

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
==============================================================================*/
#include <iostream>
#include <vector>
#include <algorithm>
#include <boost/phoenix/statement.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/phoenix/core.hpp>

int
main()
{
    using boost::phoenix::if_;
    using boost::phoenix::arg_names::arg1;

    int init[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    std::vector<int> v(init, init+10);

    std::cout << std::dec;
    int x = 0;

    std::for_each(v.begin(), v.end(),
        if_(arg1 > 5)
        [
            std::cout << arg1 << ", "
        ]
    );

    std::cout << std::endl;

    return 0;
}


text:
#include <memory.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <fstream>
#include <cpprest/http_client.h>
#include <boost/algorithm/string/predicate.hpp>

#include "Process.h"
#include "../utils/Logger.h"
#include "../utils/String.h"
#include "../common/ErrorCodes.h"
#include "../utils/WriterLock.h"
#include "../data/OutputData.h"
#include "HttpHelper.h"

using namespace hpc::core;
using namespace hpc::utils;
using namespace hpc::common;
using namespace hpc::data;
using namespace http;

Process::Process(
    int jobId,
    int taskId,
    int requeueCount,
    const std::string& taskExecutionName,
    const std::string& cmdLine,
    const std::string& standardOut,
    const std::string& standardErr,
    const std::string& standardIn,
    const std::string& workDir,
    const std::string& user,
    bool dumpStdoutToExecutionMessage,
    std::vector<uint64_t>&& cpuAffinity,
    std::map<std::string, std::string>&& envi,
    const std::function<Callback> completed) :
    jobId(jobId), taskId(taskId), requeueCount(requeueCount), taskExecutionId(String::Join("_", taskExecutionName, jobId, taskId, requeueCount)),
    commandLine(cmdLine), stdOutFile(standardOut), stdErrFile(standardErr), stdInFile(standardIn),
    workDirectory(workDir), userName(user.empty() ? "root" : user), dockerImage(envi["CCP_DOCKER_IMAGE"]), dumpStdout(dumpStdoutToExecutionMessage),
    affinity(cpuAffinity), environments(envi), callback(completed), processId(0)
{
    this->streamOutput = StartWithHttpOrHttps(stdOutFile);

    Logger::Debug(this->jobId, this->taskId, this->requeueCount, "{0}, stream ? {1}", stdOutFile, this->streamOutput);
}

Process::~Process()
{
    Logger::Debug(this->jobId, this->taskId, this->requeueCount, "~Process");
    this->Kill();

    pthread_rwlock_destroy(&this->lock);
}

void Process::Cleanup()
{
    std::string output;
    System::ExecuteCommandOut(output, "/bin/bash", "CleanupAllTasks.sh");
    Logger::Info("Cleanup zombie result: {0}", output);
}

pplx::task<std::pair<pid_t, pthread_t>> Process::Start(std::shared_ptr<Process> self)
{
    this->SetSelfPtr(self);
    pthread_create(&this->threadId, nullptr, ForkThread, this);

    Logger::Debug(this->jobId, this->taskId, this->requeueCount, "Created thread {0}", this->threadId);

    return pplx::task<std::pair<pid_t, pthread_t>>(this->started);
}

void Process::Kill(int forcedExitCode, bool forced)
{
    if (forcedExitCode != 0x0FFFFFFF)
    {
        Logger::Debug(this->jobId, this->taskId, this->requeueCount, "Setting forced ExitCode {0}", forcedExitCode);
        this->SetExitCode(forcedExitCode);
    }

    if (!this->ended)
    {
        this->ExecuteCommand("/bin/bash", "EndTask.sh", this->taskExecutionId, this->processId, forced ? "1" : "0", this->taskFolder);
    }
}

const ProcessStatistics& Process::GetStatisticsFromCGroup()
{
    std::string stat;
    System::ExecuteCommandOut(stat, "/bin/bash", "Statistics.sh", this->taskExecutionId, this->taskFolder);

    Logger::Debug(this->jobId, this->taskId, this->requeueCount, "Statistics: {0}", stat);

    std::istringstream statIn(stat);

    WriterLock writerLock(&this->lock);
    statIn >> this->statistics.UserTimeMs;
    this->statistics.UserTimeMs *= 10;

    statIn >> this->statistics.KernelTimeMs;
    this->statistics.KernelTimeMs *= 10;

    statIn >> this->statistics.WorkingSetKb;
    Logger::Debug(this->jobId, this->taskId, this->requeueCount, "WorkingSet {0}", this->statistics.WorkingSetKb);
    this->statistics.WorkingSetKb /= 1024;

    this->statistics.ProcessIds.clear();

    int id;
    while (statIn >> id)
    {
        this->statistics.ProcessIds.push_back(id);
    }

    return this->statistics;
}

pplx::task<void> Process::OnCompleted()
{
    return pplx::task<void>(this->completed);
}

void Process::OnCompletedInternal()
{
    try
    {
        this->completed.set();

        this->callback(
            this->exitCode,
            this->message.str(),
            this->statistics);
    }
    catch (const std::exception& ex)
    {
        Logger::Error(this->jobId, this->taskId, this->requeueCount, "Exception happened when callback, ex = {0}", ex.what());
    }
    catch (...)
    {
        Logger::Error(this->jobId, this->taskId, this->requeueCount, "Unknown exception happened when callback");
    }
}

void* Process::ForkThread(void* arg)
{
    Process* const p = static_cast<Process* const>(arg);
    std::string path;

Start:
    int ret = p->CreateTaskFolder();
    if (ret != 0)
    {
        p->message << "Task " << p->taskId << ": error when create task folder, ret " << ret << std::endl;
        Logger::Error(p->jobId, p->taskId, p->requeueCount, "error when create task folder, ret {0}", ret);

        p->SetExitCode(ret);
        goto Final;
    }

    path = p->BuildScript();

    if (path.empty())
    {
        p->message << "Error when build script." << std::endl;
        Logger::Error(p->jobId, p->taskId, p->requeueCount, "Error when build script.");

        p->SetExitCode((int)ErrorCodes::BuildScriptError);
        goto Final;
    }

    if (!p->dockerImage.empty())
    {
        p -> environmentsBuffer.clear();
        std::transform(
            p->environments.cbegin(),
            p->environments.cend(),
            std::back_inserter(p->environmentsBuffer),
            [](const auto& v) { return String::Join("=", v.first, v.second); });

        std::string envFile = p->taskFolder + "/environments";
        int ret = System::WriteStringToFile(envFile, String::Join<'\n'>(p->environmentsBuffer));
        if (ret != 0)
        {
            Logger::Error(p->jobId, p->taskId, p->requeueCount, "Failed to create environment file for docker task. Exitcode: {0}", ret);
            goto Final;
        }
    }

    if (0 != p->ExecuteCommand("/bin/bash", "PrepareTask.sh", p->taskExecutionId, p->GetAffinity(), p->taskFolder, p->userName))
    {
        goto Final;
    }

    if (-1 == pipe(p->stdoutPipe))
    {
        p->message << "Error when create stdout pipe." << std::endl;
        Logger::Error(p->jobId, p->taskId, p->requeueCount, "Error when create stdout pipe.");

        p->SetExitCode(errno);
        goto Final;
    }

    p->processId = fork();

    if (p->processId < 0)
    {
        std::string errorMessage =
            errno == EAGAIN ? "number of process reached upper limit" : "not enough memory";

        p->message << "Failed to fork(), pid = " << p->processId << ", errno = " << errno
            << ", msg = " << errorMessage << std::endl;
        Logger::Error(p->jobId, p->taskId, p->requeueCount, "Failed to fork(), pid = {0}, errno = {1}, msg = {2}", p->processId, errno, errorMessage);

        p->SetExitCode(errno);
        p->started.set(std::pair<pid_t, pthread_t>(p->processId, p->threadId));
        goto Final;
    }

    if (p->processId == 0)
    {
        p->Run(path);
    }
    else
    {
        assert(p->processId > 0);
        p->started.set(std::pair<pid_t, pthread_t>(p->processId, p->threadId));
        p->Monitor();
    }

Final:
    p->ExecuteCommandNoCapture("/bin/bash", "EndTask.sh", p->taskExecutionId, p->processId, "1", p->taskFolder);
    p->GetStatisticsFromCGroup();

    ret = p->ExecuteCommandNoCapture("/bin/bash", "CleanupTask.sh", p->taskExecutionId, p->processId, p->taskFolder);

    // Only clean up the folder when success.
    if (p->exitCode == 0)
    {
        p->ExecuteCommandNoCapture("rm -rf", p->taskFolder);
    }

    if (p->outputThreadId != 0)
    {
        int joinret = pthread_join(p->outputThreadId, nullptr);
        if (joinret != 0)
        {
            Logger::Error(p->jobId, p->taskId, p->requeueCount, "Join the output thread id {0}, ret = {1}", p->outputThreadId, joinret);
        }

        p->outputThreadId = 0;
    }

    // TODO: Add logic to precisely define 253 error.
    if ((p->exitCode == 82 && ret == 96) || p->exitCode == 253)
    {
        p->exitCodeSet = false;
        p->exitCode = (int)hpc::common::ErrorCodes::DefaultExitCode;
        Logger::Error(p->jobId, p->taskId, p->requeueCount, "Exit Code {0} Reset exit code and retry to fork()", p->exitCode);
        goto Start;
    }

    p->ended = true;

    auto tmp = p->stdErr.str();
    if (!tmp.empty()) { p->message << tmp; }

    p->OnCompletedInternal();

    p->ResetSelfPtr();

    pthread_detach(pthread_self());
    pthread_exit(nullptr);
}

void* Process::ReadPipeThread(void* p)
{
    Logger::Info("Started reading pipe thread");
    auto* process = static_cast<Process*>(p);

    const std::string& uri = process->stdOutFile;
    close(process->stdoutPipe[1]);

    int bytesRead = 0;
    char buffer[1024];
    int order = 0;
    while ((bytesRead = read(process->stdoutPipe[0], buffer, sizeof(buffer) - 1)) > 0)
    {
        buffer[bytesRead] = '\0';
        auto readStr = String::Join("", buffer);

        Logger::Debug("read {0} bytes, streamOutput {1}", bytesRead, process->streamOutput);
        if (process->streamOutput)
        {
            // send out readStr
            process->SendbackOutput(uri, readStr, order++);
        }
        else
        {
            process->stdErr << buffer;
        }
    }

    Logger::Debug("read end. treamOutput {0}", process->streamOutput);
    if (process->streamOutput)
    {
        process->SendbackOutput(uri, std::string(), order++);
    }

    close(process->stdoutPipe[0]);

    pthread_exit(nullptr);
}

void Process::SendbackOutput(const std::string& uri, const std::string& output, int order) const
{
    try
    {
        OutputData od(System::GetNodeName(), order, output);

        if (output.empty()) { od.Eof = true; }

        auto jsonBody = od.ToJson();
        if (!jsonBody.is_null())
        {
            Logger::Debug(this->jobId, this->taskId, this->requeueCount,
                "Callback to {0} with {1}", uri, jsonBody);

            auto client = HttpHelper::GetHttpClient(uri);
            auto request = HttpHelper::GetHttpRequest(methods::POST, jsonBody);
            http_response response = client->request(*request).get();

            Logger::Info(this->jobId, this->taskId, this->requeueCount,
                "Callback to {0} response code {1}", uri, response.status_code());
        }
    }
    catch (const std::exception& ex)
    {
        Logger::Error(this->jobId, this->taskId, this->requeueCount,
            "Exception when sending back output. {0}", ex.what());
    }
}

void Process::Monitor()
{
    assert(this->processId > 0);
    Logger::Debug(this->jobId, this->taskId, this->requeueCount, "Monitor the forked process {0}", this->processId);

    pthread_create(&this->outputThreadId, nullptr, Process::ReadPipeThread, this);

    int status;
    rusage usage;
    assert(this->processId > 0);
    pid_t waitedPid = wait4(this->processId, &status, 0, &usage);
    assert(this->processId > 0);
    if (waitedPid == -1)
    {
        Logger::Error(this->jobId, this->taskId, this->requeueCount, "wait4 for process {0} error {1}", this->processId, errno);
        this->message << "wait4 for process " << this->processId << " error " << errno << std::endl;
        this->SetExitCode(errno);

        return;
    }

    assert(this->processId > 0);
    if (waitedPid != this->processId)
    {
        Logger::Error(this->jobId, this->taskId, this->requeueCount,
            "Process {0}: waited {1}, errno {2}", this->processId, waitedPid, errno);
        assert(false);

        return;
    }

    if (WIFEXITED(status))
    {
        Logger::Info(this->jobId, this->taskId, this->requeueCount,
            "Process {0}: exit code {1}", this->processId, WEXITSTATUS(status));
        this->SetExitCode(WEXITSTATUS(status));

        if (!this->streamOutput)
        {
            std::string output;

            int ret = 0;
            if (this->dumpStdout)
            {
                ret = System::ExecuteCommandOut(output, "head -c 1500", this->stdOutFile);
                if (ret == 0)
                {
                    this->message << "STDOUT: " << output << std::endl;
                }
            }

            if (this->stdOutFile != this->stdErrFile)
            {
                ret = System::ExecuteCommandOut(output, "head -c 1500", this->stdErrFile);
                if (ret == 0)
                {
                    this->message << "STDERR: " << output << std::endl;
                }
            }
        }
    }
    else
    {
        if (WIFSIGNALED(status))
        {
            Logger::Info(this->jobId, this->taskId, this->requeueCount, "Process {0}: WIFSIGNALED Signal {1}", this->processId, WTERMSIG(status));
            this->message << "Process " << this->processId << ": WIFSIGNALED Signal " << WTERMSIG(status) << std::endl;
        }

        if (WCOREDUMP(status))
        {
            Logger::Info(this->jobId, this->taskId, this->requeueCount, "Process {0}: Core dumped.", this->processId);
            this->message << "Process " << this->processId << ": Core dumped." << std::endl;
        }

        Logger::Error(this->jobId, this->taskId, this->requeueCount, "Process {0}: wait4 status {1}", this->processId, status);
        this->SetExitCode(status);

        this->message << "Process " << this->processId << ": wait4 status " << status << std::endl;
    }

    Logger::Debug(this->jobId, this->taskId, this->requeueCount, "Process {0}: Monitor ended", this->processId);
}

void Process::Run(const std::string& path)
{
    if (this->streamOutput)
    {
        // in clusrun case, only monitor stdout, because stderr will be redirected
        // to stdout
        dup2(this->stdoutPipe[1], 1);
    }
    else
    {
        // in normal case, only monitor error messages from our own script
        // customer script output will be redirected to the stdout/stderr file directly.
        dup2(this->stdoutPipe[1], 2);
    }

    close(this->stdoutPipe[0]);
    close(this->stdoutPipe[1]);

    std::vector<char> pathBuffer(path.cbegin(), path.cend());
    pathBuffer.push_back('\0');

    char* const args[] =
    {
        const_cast<char* const>("/bin/bash"),
        const_cast<char* const>("StartTask.sh"),
        const_cast<char* const>(this->taskExecutionId.c_str()),
        &pathBuffer[0],
        const_cast<char* const>(this->userName.c_str()),
        const_cast<char* const>(this->taskFolder.c_str()),
        nullptr
    };

    auto envi = this->PrepareEnvironment();

    int ret = execvpe(args[0], args, const_cast<char* const*>(envi.get()));

    assert(ret == -1);

    std::cout << "Error occurred when execvpe, errno = " << errno << std::endl;

    exit(errno);
}

std::string Process::GetAffinity()
{
    int cores, sockets;
    System::CPU(cores, sockets);

    std::string aff;
    if (!this->affinity.empty())
    {
        std::ostringstream result;
        for (int lastCore = 0, i = 0; i < cores; i++)
        {
            size_t affinityIndex = i / 64;
            int affinityOffset = i % 64;

            if (this->affinity.size() <= affinityIndex)
            {
                OutputAffinity(result, lastCore, i - 1);

                break;
            }

            uint64_t currentAffinity = this->affinity[affinityIndex];

            if (!((currentAffinity >> affinityOffset) << (63 - affinityOffset)))
            {
                // if the bit is not set;
                OutputAffinity(result, lastCore, i - 1);

                lastCore = i + 1;
            }
            else if (i == cores - 1)
            {
                OutputAffinity(result, lastCore, i);
            }
        }

        aff = result.str();
    }

    if (aff.size() > 1)
    {
        return aff.substr(1);
    }
    else
    {
        return String::Join("-", "0", cores - 1);
    }
}

int Process::CreateTaskFolder()
{
    char folder[256];

    sprintf(folder, "/tmp/nodemanager_task_%d_%d.XXXXXX", this->taskId, this->requeueCount);

    int ret = System::CreateTempFolder(folder, this->userName);

    if (ret != 0)
    {
        Logger::Debug(this->jobId, this->taskId, this->requeueCount, "CreateTaskFolder failed exitCode {0}.", ret);
    }

    this->taskFolder = folder;

    return ret;
}

std::string Process::BuildScript()
{
    std::string cmd = this->taskFolder + "/cmd.sh";
    std::ofstream fsCmd(cmd, std::ios::trunc);
    fsCmd << "#!/bin/bash" << std::endl << std::endl;
    fsCmd << this->commandLine << std::endl;
    fsCmd.close();

    std::string runDirInOut = this->taskFolder + "/run_dir_in_out.sh";

    std::ofstream fs(runDirInOut, std::ios::trunc);
    fs << "#!/bin/bash" << std::endl << std::endl;

    Logger::Debug("{0}, {1}", this->taskFolder, this->workDirectory);

    std::string workDirectory = this->workDirectory.empty() ? this->taskFolder : this->workDirectory;
    fs << "cd " << workDirectory << " || exit $?" << std::endl << std::endl;

    if (this->stdOutFile.empty()) this->stdOutFile = this->taskFolder + "/stdout.txt";
    else if (!boost::algorithm::starts_with(this->stdOutFile, "/") && !StartWithHttpOrHttps(this->stdOutFile)) this->stdOutFile = workDirectory + "/" + this->stdOutFile;
    if (this->stdErrFile.empty()) this->stdErrFile = this->taskFolder + "/stderr.txt";
    else if (!boost::algorithm::starts_with(this->stdErrFile, "/") && !StartWithHttpOrHttps(this->stdErrFile)) this->stdErrFile = workDirectory + "/" + this->stdErrFile;

    // before
    fs << "echo before >" << this->taskFolder << "/before1.txt 2>" << this->taskFolder << "/before2.txt";
    fs << " || ([ \"$?\" = \"1\" ] && exit 253)" << std::endl;

    // test
    fs << "echo test >" << this->taskFolder << "/stdout.txt 2>" << this->taskFolder << "/stderr.txt";
    fs << " || ([ \"$?\" = \"1\" ] && exit 253)" << std::endl << std::endl;

    // run
    if (this->streamOutput)
    {
        fs << "/bin/bash " << cmd << " 2>&1";
    }
    else if (this->stdOutFile == this->stdErrFile)
    {
        fs << "/bin/bash " << cmd << " >" << this->stdOutFile << " 2>&1";
    }
    else
    {
        fs << "/bin/bash " << cmd << " >" << this->stdOutFile << " 2>" << this->stdErrFile;
    }

    if (!this->stdInFile.empty())
    {
        fs << " <" << this->stdInFile;
    }

    fs << std::endl;
    fs << "ec=$?" << std::endl;
    fs << "[ $ec -ne 0 ] && exit $ec" << std::endl;

    fs << std::endl << std::endl;

    // after
    fs << "echo after >" << this->taskFolder << "/after1.txt 2>" << this->taskFolder << "/after2.txt";
    fs << " || ([ \"$?\" = \"1\" ] && exit 253)" << std::endl;

    fs.close();

    return std::move(runDirInOut);
}

std::unique_ptr<const char* []> Process::PrepareEnvironment()
{
    this->environmentsBuffer.clear();

    auto it = this->environments.find(std::string("PATH"));

    if (it == this->environments.end())
    {
        char* currentPath = getenv("PATH");
        this->environmentsBuffer.push_back(std::string("PATH=") + currentPath);
    }

    std::transform(
        this->environments.cbegin(),
        this->environments.cend(),
        std::back_inserter(this->environmentsBuffer),
        [](const auto& v) { return String::Join("=", v.first, v.second); });

    auto envi = std::unique_ptr<const char* []>(new const char*[this->environments.size() + 1]);
    int p = 0;
    for_each(
        this->environmentsBuffer.cbegin(),
        this->environmentsBuffer.cend(),
        [&p, &envi](const auto& i) { envi[p++] = i.c_str(); });

    envi[p] = nullptr;

    return std::move(envi);
}

std::string Process::PeekOutput()
{
    std::string output;

    int ret = 0;
    std::string stdout;
    ret = System::ExecuteCommandOut(stdout, "tail -c 5000 2>&1", this->stdOutFile);
    if (ret != 0)
    {
        stdout = String::Join(" ", "Reading", this->stdOutFile, "failed with exitcode", ret, ":", stdout);
    }

    output = stdout;

    if (this->stdOutFile != this->stdErrFile)
    {
        std::string stderr;
        ret = System::ExecuteCommandOut(stderr, "tail -c 5000 2>&1", this->stdErrFile);
        if (ret != 0)
        {
            stderr = String::Join(" ", "Reading", this->stdErrFile, "failed with exitcode", ret, ":", stderr);
        }

        output = String::Join("\n", "STDOUT:", stdout, "STDERR:", stderr);
    }

    return output;
}

max_stars_repo_name: Azure/hpcpack-linux-agent

max_issues_repo_name: coolmay/whpc-linux-communicator

max_forks_repo_name: coolmay/whpc-linux-communicator