<commit_before>// Copyright (C) 2018 Egor Pugin <egor.pugin@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <boost/asio/io_context.hpp>

#include <primitives/command.h>

#include <boost/algorithm/string.hpp>
#include <boost/asio/use_future.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/nowide/convert.hpp>
#include <boost/process.hpp>

#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>

auto &get_io_context()
{
    static boost::asio::io_context io_context;
    // protect context from being stopped
    static auto wg = boost::asio::make_work_guard(io_context);
    return io_context;
}

namespace primitives
{

namespace bp = boost::process;

struct CommandData
{
    using cb_func = std::function<void(const boost::system::error_code &, std::size_t)>;

    boost::asio::io_context &ios;
    boost::process::async_pipe pout, perr;

    cb_func out_cb, err_cb;

    std::vector<char> out_buf, err_buf;
    FILE *out_fs = nullptr;
    FILE *err_fs = nullptr;

    std::mutex m;
    std::condition_variable cv;
    std::atomic_int stopped{ 0 };

    // TODO: add pid and option to command to execute callbacks right in this thread

    CommandData(boost::asio::io_context &ios)
        : ios(ios), pout(ios), perr(ios)
    {
    }

    ~CommandData()
    {
        if (out_fs)
            fclose(out_fs);
        if (err_fs)
            fclose(err_fs);
    }
};

path resolve_executable(const path &p)
{
#ifdef _WIN32
    static const std::vector<String> exts = []
    {
        String s = getenv("PATHEXT");
        boost::to_lower(s);
        std::vector<String> exts;
        boost::split(exts, s, boost::is_any_of(";"));
        return exts;
    }();
    if (p.has_extension() &&
        std::find(exts.begin(), exts.end(), boost::to_lower_copy(p.extension().string())) != exts.end() &&
        fs::exists(p) &&
        fs::is_regular_file(p)
        )
        return p;
    // do not test direct file
    if (fs::exists(p) && fs::is_regular_file(p))
        return p;
    // failed, test new exts
    for (auto &e : exts)
    {
        auto p2 = p;
        p2 += e;
        if (fs::exists(p2) && fs::is_regular_file(p2))
            return p2;
    }
#else
    if (fs::exists(p) && fs::is_regular_file(p))
        return p;
#endif
    return bp::search_path(p.wstring()).wstring();
}

path resolve_executable(const std::vector<path> &paths)
{
    for (auto &p : paths)
    {
        auto e = resolve_executable(p);
        if (!e.empty())
            return e;
    }
    return path();
}

String Command::print() const
{
    String s;
    s += "\"" + program.u8string() + "\" ";
    for (auto &a : args)
        s += "\"" + a + "\" ";
    s.resize(s.size() - 1);
    return s;
}

void Command::execute1(std::error_code *ec_in)
{
    // setup

    // try to use first arg as a program
    if (program.empty())
    {
        if (args.empty())
            throw std::runtime_error("No program was set");
        program = args[0];
        auto t = std::move(args);
        args.assign(t.begin() + 1, t.end());
    }

    // resolve exe
    {
        auto p = resolve_executable(program);
        if (p.empty())
        {
            auto e = "Cannot resolve executable: " + program.u8string();
            if (!ec_in)
                throw std::runtime_error(e);
            *ec_in = std::make_error_code(std::errc::no_such_file_or_directory);
            err.text = e;
            return;
        }
        program = p;
    }

    if (working_directory.empty())
        working_directory = current_thread_path();

#ifdef _WIN32
    // widen args
    std::vector<std::wstring> wargs;
    for (auto &a : args)
        wargs.push_back(boost::nowide::widen(a));
#else
    const Strings &wargs = args;
#endif

    // local scope, so we automatically close and destroy everything on exit
    CommandData d(get_io_context());

    auto async_read = [this, &cv = d.cv, &d](const boost::system::error_code &ec, std::size_t s,
        auto &out, auto &p, auto &out_buf, auto &&out_cb, auto &out_fs, auto &stream)
    {
        if (s)
        {
            String str(out_buf.begin(), out_buf.begin() + s);
            out.text += str;
            if (inherit || out.inherit)
            {
                // ???
                if (!stream)
                    stream.clear();
                stream << str;
            }
            if (out.action)
                out.action(str, !!ec);
            if (!out.file.empty())
                fwrite(&str[0], str.size(), 1, out_fs);
        }

        if (!ec)
        {
            p.async_read_some(boost::asio::buffer(out_buf), out_cb);
        }
        else
        {
            // win32: ec = 109, pipe is ended
            if (p.is_open())
            {
                if (s)
                {
                    p.async_close();
                    p.close();
                    assert(false && "non zero message with closed pipe");
                    throw std::runtime_error("primitives.command (" + std::to_string(__LINE__) + "): non zero message with closed pipe");
                }
                else
                    p.close();
            }
            // if we somehow hit this w/o p.is_open(),
            // we still consider pipe as closed and notice users
            cv.notify_all();
            d.stopped++;
        }
    };

    d.out_cb = [this, &d, &async_read](const boost::system::error_code &ec, std::size_t s)
    {
        async_read(ec, s, out, d.pout, d.out_buf, d.out_cb,
            d.out_fs,
            std::cout);
    };
    d.err_cb = [this, &d, &async_read](const boost::system::error_code &ec, std::size_t s)
    {
        async_read(ec, s, err, d.perr, d.err_buf, d.err_cb,
            out.file != err.file ? d.err_fs : d.out_fs,
            std::cerr);
    };

    // setup buffers
    d.out_buf.resize(buf_size);
    d.err_buf.resize(buf_size);

    // move this after process start?
    // make a copy there below?
    d.pout.async_read_some(boost::asio::buffer(d.out_buf), d.out_cb);
    d.perr.async_read_some(boost::asio::buffer(d.err_buf), d.err_cb);

    // run
    auto on_exit = [](int exit, const std::error_code& ec_in)
    {
        // must be empty, pipes are closed in async_read_some() funcs
        //d.pout.async_close();
        //d.perr.async_close();
    };

    std::error_code ec;
    auto error = [this, &ec_in, &ec]()
    {
        if (ec_in)
        {
            *ec_in = ec;
            return;
        }
        throw std::runtime_error("Last command failed: " + print() + ", ec = " + ec.message());
    };

    bp::child c;
    if (!out.file.empty() || !err.file.empty())
    {
        if (!out.file.empty() && !err.file.empty())
        {
            c = bp::child(
                program.wstring()
                , bp::args = wargs
                , bp::start_dir = working_directory.wstring()

                , bp::std_in < stdin
                , bp::std_out > out.file
                , bp::std_err > err.file

                , ec // always use ec
            );
            if (ec)
                error();
            c.wait();
            return;
        }
        else if (!out.file.empty())
        {
            c = bp::child(
                program.wstring()
                , bp::args = wargs
                , bp::start_dir = working_directory.wstring()

                , bp::std_in < stdin
                , bp::std_out > out.file
                , bp::std_err > d.perr

                , ec // always use ec

                , d.ios
                // Without this line boost::process does not work well on linux
                // in current setup.
                // It cannot detect empty pipes.
                , bp::on_exit(on_exit)
            );
            d.pout.close();
            d.stopped++;
        }
        else if (!err.file.empty())
        {
            c = bp::child(
                program.wstring()
                , bp::args = wargs
                , bp::start_dir = working_directory.wstring()

                , bp::std_in < stdin
                , bp::std_out > d.pout
                , bp::std_err > err.file

                , ec // always use ec

                , d.ios
                // Without this line boost::process does not work well on linux
                // in current setup.
                // It cannot detect empty pipes.
                , bp::on_exit(on_exit)
            );
            d.perr.close();
            d.stopped++;
        }
    }
    else
    {
        c = bp::child(
            program.wstring()
            , bp::args = wargs
            , bp::start_dir = working_directory.wstring()

            , bp::std_in < stdin
            , bp::std_out > d.pout
            , bp::std_err > d.perr

            , ec // always use ec

            , d.ios
            // Without this line boost::process does not work well on linux
            // in current setup.
            // It cannot detect empty pipes.
            , bp::on_exit(on_exit)
        );
    }

    // some critical error during process creation
    if (/*!c || */ec)
    {
        while (c.running())
            d.ios.poll_one();
        while (d.pout.is_open() || d.perr.is_open())
            d.ios.poll_one();

        error();
    }

    using namespace std::literals::chrono_literals;

    auto delay = 100ms;
    const auto max = 1s;
    while (c.running())
    {
        // in case we're done or two pipes were closed, we do not wait in cv anymore
        if (d.ios.poll_one())
        {
            delay = 100ms;
            continue;
        }
        // no jobs available, do a small sleep waiting for process
        delay = delay > max ? max : delay;
        c.wait_for(delay);
        delay += 100ms;
    }

    while (d.pout.is_open() || d.perr.is_open())
    {
        // in case we're done or two pipes were closed, we do not wait in cv anymore
        if (d.ios.poll_one())
        {
            delay = 100ms;
            continue;
        }

        // no jobs available, do a small sleep waiting for pipes closed
        std::unique_lock<std::mutex> lk(d.m);
        delay = delay > max ? max : delay;
        d.cv.wait_for(lk, delay, [&d] {return !d.pout.is_open() && !d.perr.is_open(); });
        delay += 100ms;
    }

    // cv notifcation may hang a bit, so in async handler it will be called on destroyed object
    while (d.stopped != 2)
    {
        // in case we're done or two pipes were closed, we do not wait in cv anymore
        if (d.ios.poll_one())
        {
            delay = 100ms;
            continue;
        }

        // no jobs available, do a small sleep waiting for pipes closed
        std::unique_lock<std::mutex> lk(d.m);
        delay = delay > max ? max : delay;
        d.cv.wait_for(lk, delay, [&d] {return d.stopped == 2; });
        delay += 100ms;
    }

    exit_code = c.exit_code();

    // return if ok
    if (exit_code.value() == 0)
        return;
    else if (ec_in)
    {
        ec_in->assign(exit_code.value(), std::generic_category());
        return;
    }

    throw std::runtime_error("Last command failed: " + print() + ", exit code = " + std::to_string(exit_code.value()));
}

void Command::write(path p) const
{
    auto fn = p.filename().string();
    p = p.parent_path();
    write_file(p / (fn + "_out.txt"), out.text);
    write_file(p / (fn + "_err.txt"), err.text);
}

void Command::execute1(const path &p, const Strings &args, std::error_code *ec)
{
    Command c;
    c.program = p;
    c.args = args;
    c.execute1(ec);
}

void Command::execute(const path &p)
{
    execute1(p);
}

void Command::execute(const path &p, std::error_code &ec)
{
    execute1(p, Strings(), &ec);
}

void Command::execute(const path &p, const Strings &args)
{
    execute1(p, args);
}

void Command::execute(const path &p, const Strings &args, std::error_code &ec)
{
    execute1(p, args, &ec);
}

void Command::execute(const Strings &args)
{
    Command c;
    c.args = args;
    c.execute();
}

void Command::execute(const Strings &args, std::error_code &ec)
{
    Command c;
    c.args = args;
    c.execute(ec);
}

void Command::execute(const std::initializer_list<String> &args)
{
    execute(Strings(args.begin(), args.end()));
}

void Command::execute(const std::initializer_list<String> &args, std::error_code &ec)
{
    execute(Strings(args.begin(), args.end()), ec);
}

}
<commit_msg>Remove unneeded increments.<commit_after>// Copyright (C) 2018 Egor Pugin <egor.pugin@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include <boost/asio/io_context.hpp>

#include <primitives/command.h>

#include <boost/algorithm/string.hpp>
#include <boost/asio/use_future.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/nowide/convert.hpp>
#include <boost/process.hpp>

#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>

auto &get_io_context()
{
    static boost::asio::io_context io_context;
    // protect context from being stopped
    static auto wg = boost::asio::make_work_guard(io_context);
    return io_context;
}

namespace primitives
{

namespace bp = boost::process;

struct CommandData
{
    using cb_func = std::function<void(const boost::system::error_code &, std::size_t)>;

    boost::asio::io_context &ios;
    boost::process::async_pipe pout, perr;

    cb_func out_cb, err_cb;

    std::vector<char> out_buf, err_buf;
    FILE *out_fs = nullptr;
    FILE *err_fs = nullptr;

    std::mutex m;
    std::condition_variable cv;
    std::atomic_int stopped{ 0 };

    // TODO: add pid and option to command to execute callbacks right in this thread

    CommandData(boost::asio::io_context &ios)
        : ios(ios), pout(ios), perr(ios)
    {
    }

    ~CommandData()
    {
        if (out_fs)
            fclose(out_fs);
        if (err_fs)
            fclose(err_fs);
    }
};

path resolve_executable(const path &p)
{
#ifdef _WIN32
    static const std::vector<String> exts = []
    {
        String s = getenv("PATHEXT");
        boost::to_lower(s);
        std::vector<String> exts;
        boost::split(exts, s, boost::is_any_of(";"));
        return exts;
    }();
    if (p.has_extension() &&
        std::find(exts.begin(), exts.end(), boost::to_lower_copy(p.extension().string())) != exts.end() &&
        fs::exists(p) &&
        fs::is_regular_file(p)
        )
        return p;
    // do not test direct file
    if (fs::exists(p) && fs::is_regular_file(p))
        return p;
    // failed, test new exts
    for (auto &e : exts)
    {
        auto p2 = p;
        p2 += e;
        if (fs::exists(p2) && fs::is_regular_file(p2))
            return p2;
    }
#else
    if (fs::exists(p) && fs::is_regular_file(p))
        return p;
#endif
    return bp::search_path(p.wstring()).wstring();
}

path resolve_executable(const std::vector<path> &paths)
{
    for (auto &p : paths)
    {
        auto e = resolve_executable(p);
        if (!e.empty())
            return e;
    }
    return path();
}

String Command::print() const
{
    String s;
    s += "\"" + program.u8string() + "\" ";
    for (auto &a : args)
        s += "\"" + a + "\" ";
    s.resize(s.size() - 1);
    return s;
}

void Command::execute1(std::error_code *ec_in)
{
    // setup

    // try to use first arg as a program
    if (program.empty())
    {
        if (args.empty())
            throw std::runtime_error("No program was set");
        program = args[0];
        auto t = std::move(args);
        args.assign(t.begin() + 1, t.end());
    }

    // resolve exe
    {
        auto p = resolve_executable(program);
        if (p.empty())
        {
            auto e = "Cannot resolve executable: " + program.u8string();
            if (!ec_in)
                throw std::runtime_error(e);
            *ec_in = std::make_error_code(std::errc::no_such_file_or_directory);
            err.text = e;
            return;
        }
        program = p;
    }

    if (working_directory.empty())
        working_directory = current_thread_path();

#ifdef _WIN32
    // widen args
    std::vector<std::wstring> wargs;
    for (auto &a : args)
        wargs.push_back(boost::nowide::widen(a));
#else
    const Strings &wargs = args;
#endif

    // local scope, so we automatically close and destroy everything on exit
    CommandData d(get_io_context());

    auto async_read = [this, &cv = d.cv, &d](const boost::system::error_code &ec, std::size_t s,
        auto &out, auto &p, auto &out_buf, auto &&out_cb, auto &out_fs, auto &stream)
    {
        if (s)
        {
            String str(out_buf.begin(), out_buf.begin() + s);
            out.text += str;
            if (inherit || out.inherit)
            {
                // ???
                if (!stream)
                    stream.clear();
                stream << str;
            }
            if (out.action)
                out.action(str, !!ec);
            if (!out.file.empty())
                fwrite(&str[0], str.size(), 1, out_fs);
        }

        if (!ec)
        {
            p.async_read_some(boost::asio::buffer(out_buf), out_cb);
        }
        else
        {
            // win32: ec = 109, pipe is ended
            if (p.is_open())
            {
                if (s)
                {
                    p.async_close();
                    p.close();
                    assert(false && "non zero message with closed pipe");
                    throw std::runtime_error("primitives.command (" + std::to_string(__LINE__) + "): non zero message with closed pipe");
                }
                else
                    p.close();
            }
            // if we somehow hit this w/o p.is_open(),
            // we still consider pipe as closed and notice users
            cv.notify_all();
            d.stopped++;
        }
    };

    d.out_cb = [this, &d, &async_read](const boost::system::error_code &ec, std::size_t s)
    {
        async_read(ec, s, out, d.pout, d.out_buf, d.out_cb,
            d.out_fs,
            std::cout);
    };
    d.err_cb = [this, &d, &async_read](const boost::system::error_code &ec, std::size_t s)
    {
        async_read(ec, s, err, d.perr, d.err_buf, d.err_cb,
            out.file != err.file ? d.err_fs : d.out_fs,
            std::cerr);
    };

    // setup buffers
    d.out_buf.resize(buf_size);
    d.err_buf.resize(buf_size);

    // move this after process start?
    // make a copy there below?
    d.pout.async_read_some(boost::asio::buffer(d.out_buf), d.out_cb);
    d.perr.async_read_some(boost::asio::buffer(d.err_buf), d.err_cb);

    // run
    auto on_exit = [](int exit, const std::error_code& ec_in)
    {
        // must be empty, pipes are closed in async_read_some() funcs
        //d.pout.async_close();
        //d.perr.async_close();
    };

    std::error_code ec;
    auto error = [this, &ec_in, &ec]()
    {
        if (ec_in)
        {
            *ec_in = ec;
            return;
        }
        throw std::runtime_error("Last command failed: " + print() + ", ec = " + ec.message());
    };

    bp::child c;
    if (!out.file.empty() || !err.file.empty())
    {
        if (!out.file.empty() && !err.file.empty())
        {
            c = bp::child(
                program.wstring()
                , bp::args = wargs
                , bp::start_dir = working_directory.wstring()

                , bp::std_in < stdin
                , bp::std_out > out.file
                , bp::std_err > err.file

                , ec // always use ec
            );
            if (ec)
                error();
            c.wait();
            return;
        }
        else if (!out.file.empty())
        {
            c = bp::child(
                program.wstring()
                , bp::args = wargs
                , bp::start_dir = working_directory.wstring()

                , bp::std_in < stdin
                , bp::std_out > out.file
                , bp::std_err > d.perr

                , ec // always use ec

                , d.ios
                // Without this line boost::process does not work well on linux
                // in current setup.
                // It cannot detect empty pipes.
                , bp::on_exit(on_exit)
            );
            d.pout.close();
            // do not increment d.stopped here,
            // because asio will still call that callback once
        }
        else if (!err.file.empty())
        {
            c = bp::child(
                program.wstring()
                , bp::args = wargs
                , bp::start_dir = working_directory.wstring()

                , bp::std_in < stdin
                , bp::std_out > d.pout
                , bp::std_err > err.file

                , ec // always use ec

                , d.ios
                // Without this line boost::process does not work well on linux
                // in current setup.
                // It cannot detect empty pipes.
                , bp::on_exit(on_exit)
            );
            d.perr.close();
            // do not increment d.stopped here,
            // because asio will still call that callback once
        }
    }
    else
    {
        c = bp::child(
            program.wstring()
            , bp::args = wargs
            , bp::start_dir = working_directory.wstring()

            , bp::std_in < stdin
            , bp::std_out > d.pout
            , bp::std_err > d.perr

            , ec // always use ec

            , d.ios
            // Without this line boost::process does not work well on linux
            // in current setup.
            // It cannot detect empty pipes.
            , bp::on_exit(on_exit)
        );
    }

    // some critical error during process creation
    if (/*!c || */ec)
    {
        while (c.running())
            d.ios.poll_one();
        while (d.pout.is_open() || d.perr.is_open())
            d.ios.poll_one();

        error();
    }

    using namespace std::literals::chrono_literals;

    auto delay = 100ms;
    const auto max = 1s;
    while (c.running())
    {
        // in case we're done or two pipes were closed, we do not wait in cv anymore
        if (d.ios.poll_one())
        {
            delay = 100ms;
            continue;
        }
        // no jobs available, do a small sleep waiting for process
        delay = delay > max ? max : delay;
        c.wait_for(delay);
        delay += 100ms;
    }

    while (d.pout.is_open() || d.perr.is_open())
    {
        // in case we're done or two pipes were closed, we do not wait in cv anymore
        if (d.ios.poll_one())
        {
            delay = 100ms;
            continue;
        }

        // no jobs available, do a small sleep waiting for pipes closed
        std::unique_lock<std::mutex> lk(d.m);
        delay = delay > max ? max : delay;
        d.cv.wait_for(lk, delay, [&d] {return !d.pout.is_open() && !d.perr.is_open(); });
        delay += 100ms;
    }

    // cv notifcation may hang a bit, so in async handler it will be called on destroyed object
    while (d.stopped != 2)
    {
        // in case we're done or two pipes were closed, we do not wait in cv anymore
        if (d.ios.poll_one())
        {
            delay = 100ms;
            continue;
        }

        // no jobs available, do a small sleep waiting for pipes closed
        std::unique_lock<std::mutex> lk(d.m);
        delay = delay > max ? max : delay;
        d.cv.wait_for(lk, delay, [&d] {return d.stopped == 2; });
        delay += 100ms;
    }

    exit_code = c.exit_code();

    // return if ok
    if (exit_code.value() == 0)
        return;
    else if (ec_in)
    {
        ec_in->assign(exit_code.value(), std::generic_category());
        return;
    }

    throw std::runtime_error("Last command failed: " + print() + ", exit code = " + std::to_string(exit_code.value()));
}

void Command::write(path p) const
{
    auto fn = p.filename().string();
    p = p.parent_path();
    write_file(p / (fn + "_out.txt"), out.text);
    write_file(p / (fn + "_err.txt"), err.text);
}

void Command::execute1(const path &p, const Strings &args, std::error_code *ec)
{
    Command c;
    c.program = p;
    c.args = args;
    c.execute1(ec);
}

void Command::execute(const path &p)
{
    execute1(p);
}

void Command::execute(const path &p, std::error_code &ec)
{
    execute1(p, Strings(), &ec);
}

void Command::execute(const path &p, const Strings &args)
{
    execute1(p, args);
}

void Command::execute(const path &p, const Strings &args, std::error_code &ec)
{
    execute1(p, args, &ec);
}

void Command::execute(const Strings &args)
{
    Command c;
    c.args = args;
    c.execute();
}

void Command::execute(const Strings &args, std::error_code &ec)
{
    Command c;
    c.args = args;
    c.execute(ec);
}

void Command::execute(const std::initializer_list<String> &args)
{
    execute(Strings(args.begin(), args.end()));
}

void Command::execute(const std::initializer_list<String> &args, std::error_code &ec)
{
    execute(Strings(args.begin(), args.end()), ec);
}

}
<|endoftext|>


<commit_before>/****************************************************************/
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*          All contents are licensed under LGPL V2.1           */
/*             See LICENSE for full restrictions                */
/****************************************************************/
#include "GeneralizedPlaneStrainAction.h"

#include "Conversion.h"
#include "FEProblem.h"
#include "MooseMesh.h"
#include "NonlinearSystemBase.h"

template <>
InputParameters
validParams<GeneralizedPlaneStrainAction>()
{
  InputParameters params = validParams<Action>();
  params.addClassDescription("Set up the GeneralizedPlaneStrain environment");
  params.addRequiredParam<std::vector<NonlinearVariableName>>("displacements",
                                                              "The displacement variables");
  params.addRequiredParam<NonlinearVariableName>("scalar_out_of_plane_strain",
                                                 "Scalar variable for the out-of-plane strain (in "
                                                 "y direction for 1D Axisymmetric or in z "
                                                 "direction for 2D Cartesian problems)");
  params.addParam<NonlinearVariableName>("temperature", "The temperature variable");
  params.addParam<FunctionName>("out_of_plane_pressure",
                                "0",
                                "Function used to prescribe pressure "
                                "in the out-of-plane direction (y "
                                "for 1D Axisymmetric or z for 2D "
                                "Cartesian problems)");
  params.addParam<Real>("factor", 1.0, "Scale factor applied to prescribed pressure");
  params.addParam<bool>("use_displaced_mesh", false, "Whether to use displaced mesh");
  params.addParam<std::string>("base_name", "Material property base name");
  params.addParam<std::vector<SubdomainName>>("block",
                                              "The list of ids of the blocks (subdomain) "
                                              "that the GeneralizedPlaneStrain kernels "
                                              "will be applied to");

  return params;
}

GeneralizedPlaneStrainAction::GeneralizedPlaneStrainAction(const InputParameters & params)
  : Action(params),
    _displacements(getParam<std::vector<NonlinearVariableName>>("displacements")),
    _ndisp(_displacements.size())
{
  if (_ndisp > 2)
    mooseError("GeneralizedPlaneStrain only works for 1D axisymmetric or 2D generalized plane "
               "strain cases!");
}

void
GeneralizedPlaneStrainAction::act()
{
  // user object name
  const std::string uo_name = _name + "_GeneralizedPlaneStrainUserObject";

  //
  // Add off diagonal Jacobian kernels
  //
  if (_current_task == "add_kernel")
  {
    std::string k_type = "GeneralizedPlaneStrainOffDiag";
    InputParameters params = _factory.getValidParams(k_type);

    params.applyParameters(parameters(), {"scalar_out_of_plane_strain"});
    params.set<std::vector<VariableName>>("scalar_out_of_plane_strain") = {
        getParam<NonlinearVariableName>("scalar_out_of_plane_strain")};

    // add off-diagonal jacobian kernels for the displacements
    for (unsigned int i = 0; i < _ndisp; ++i)
    {
      std::string k_name = _name + "GeneralizedPlaneStrainOffDiag_disp" + Moose::stringify(i);
      params.set<NonlinearVariableName>("variable") = _displacements[i];

      _problem->addKernel(k_type, k_name, params);
    }

    // add temperature kernel only if temperature is a nonlinear variable (and not an auxvariable)
    if (isParamValid("temperature") &&
        _problem->getNonlinearSystemBase().hasVariable("temperature"))
    {
      params.set<NonlinearVariableName>("temperature") =
          getParam<NonlinearVariableName>("temperature");

      std::string k_name = _name + "_GeneralizedPlaneStrainOffDiag_temp";
      params.set<NonlinearVariableName>("variable") =
          getParam<NonlinearVariableName>("temperature");

      _problem->addKernel(k_type, k_name, params);
    }
  }

  //
  // Add user object
  //
  else if (_current_task == "add_user_object")
  {
    std::string uo_type = "GeneralizedPlaneStrainUserObject";
    InputParameters params = _factory.getValidParams(uo_type);

    params.applyParameters(parameters());
    params.set<MultiMooseEnum>("execute_on") = "linear";

    _problem->addUserObject(uo_type, uo_name, params);
  }

  //
  // Add scalar kernel
  //
  else if (_current_task == "add_scalar_kernel")
  {
    std::string sk_type = "GeneralizedPlaneStrain";
    InputParameters params = _factory.getValidParams(sk_type);

    params.set<NonlinearVariableName>("variable") =
        getParam<NonlinearVariableName>("scalar_out_of_plane_strain");

    // set the UserObjectName from previously added UserObject
    params.set<UserObjectName>("generalized_plane_strain") = uo_name;

    _problem->addScalarKernel(sk_type, _name + "_GeneralizedPlaneStrain", params);
  }
}
<commit_msg>Fix issues with adding temperature kernel in generalized plane strain action (#8957)<commit_after>/****************************************************************/
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*          All contents are licensed under LGPL V2.1           */
/*             See LICENSE for full restrictions                */
/****************************************************************/
#include "GeneralizedPlaneStrainAction.h"

#include "Conversion.h"
#include "FEProblem.h"
#include "MooseMesh.h"
#include "NonlinearSystemBase.h"

template <>
InputParameters
validParams<GeneralizedPlaneStrainAction>()
{
  InputParameters params = validParams<Action>();
  params.addClassDescription("Set up the GeneralizedPlaneStrain environment");
  params.addRequiredParam<std::vector<NonlinearVariableName>>("displacements",
                                                              "The displacement variables");
  params.addRequiredParam<NonlinearVariableName>("scalar_out_of_plane_strain",
                                                 "Scalar variable for the out-of-plane strain (in "
                                                 "y direction for 1D Axisymmetric or in z "
                                                 "direction for 2D Cartesian problems)");
  params.addParam<NonlinearVariableName>("temperature", "The temperature variable");
  params.addParam<FunctionName>("out_of_plane_pressure",
                                "0",
                                "Function used to prescribe pressure "
                                "in the out-of-plane direction (y "
                                "for 1D Axisymmetric or z for 2D "
                                "Cartesian problems)");
  params.addParam<Real>("factor", 1.0, "Scale factor applied to prescribed pressure");
  params.addParam<bool>("use_displaced_mesh", false, "Whether to use displaced mesh");
  params.addParam<std::string>("base_name", "Material property base name");
  params.addParam<std::vector<SubdomainName>>("block",
                                              "The list of ids of the blocks (subdomain) "
                                              "that the GeneralizedPlaneStrain kernels "
                                              "will be applied to");

  return params;
}

GeneralizedPlaneStrainAction::GeneralizedPlaneStrainAction(const InputParameters & params)
  : Action(params),
    _displacements(getParam<std::vector<NonlinearVariableName>>("displacements")),
    _ndisp(_displacements.size())
{
  if (_ndisp > 2)
    mooseError("GeneralizedPlaneStrain only works for 1D axisymmetric or 2D generalized plane "
               "strain cases!");
}

void
GeneralizedPlaneStrainAction::act()
{
  // user object name
  const std::string uo_name = _name + "_GeneralizedPlaneStrainUserObject";

  //
  // Add off diagonal Jacobian kernels
  //
  if (_current_task == "add_kernel")
  {
    std::string k_type = "GeneralizedPlaneStrainOffDiag";
    InputParameters params = _factory.getValidParams(k_type);

    params.applyParameters(parameters(), {"scalar_out_of_plane_strain"});
    params.set<std::vector<VariableName>>("scalar_out_of_plane_strain") = {
        getParam<NonlinearVariableName>("scalar_out_of_plane_strain")};

    // add off-diagonal jacobian kernels for the displacements
    for (unsigned int i = 0; i < _ndisp; ++i)
    {
      std::string k_name = _name + "GeneralizedPlaneStrainOffDiag_disp" + Moose::stringify(i);
      params.set<NonlinearVariableName>("variable") = _displacements[i];

      _problem->addKernel(k_type, k_name, params);
    }

    // add temperature kernel only if temperature is a nonlinear variable (and not an auxvariable)
    if (isParamValid("temperature"))
    {
      NonlinearVariableName temp = getParam<NonlinearVariableName>("temperature");
      if (_problem->getNonlinearSystemBase().hasVariable(temp))
      {
        params.set<NonlinearVariableName>("temperature") = temp;

        std::string k_name = _name + "_GeneralizedPlaneStrainOffDiag_temp";
        params.set<NonlinearVariableName>("variable") = temp;

        _problem->addKernel(k_type, k_name, params);
      }
    }
  }

  //
  // Add user object
  //
  else if (_current_task == "add_user_object")
  {
    std::string uo_type = "GeneralizedPlaneStrainUserObject";
    InputParameters params = _factory.getValidParams(uo_type);

    params.applyParameters(parameters());
    params.set<MultiMooseEnum>("execute_on") = "linear";

    _problem->addUserObject(uo_type, uo_name, params);
  }

  //
  // Add scalar kernel
  //
  else if (_current_task == "add_scalar_kernel")
  {
    std::string sk_type = "GeneralizedPlaneStrain";
    InputParameters params = _factory.getValidParams(sk_type);

    params.set<NonlinearVariableName>("variable") =
        getParam<NonlinearVariableName>("scalar_out_of_plane_strain");

    // set the UserObjectName from previously added UserObject
    params.set<UserObjectName>("generalized_plane_strain") = uo_name;

    _problem->addScalarKernel(sk_type, _name + "_GeneralizedPlaneStrain", params);
  }
}
<|endoftext|>


<commit_before>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2010 Dreamhost
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "config.h"
#include "common/DoutStreambuf.h"
#include "common/errno.h"
#include "common/Mutex.h"

#include <assert.h>
#include <errno.h>
#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>
#include <streambuf>
#include <string.h>
#include <syslog.h>

///////////////////////////// Globals /////////////////////////////
// TODO: get rid of this lock using thread-local storage
extern Mutex _dout_lock;

/* True if we should output high-priority messages to stderr */
static bool use_stderr = true;

//////////////////////// Helper functions //////////////////////////
static bool empty(const char *str)
{
  if (!str)
    return true;
  if (!str[0])
    return true;
  return false;
}

static string cpp_str(const char *str)
{
  if (!str)
    return "(NULL)";
  if (str[0] == '\0')
    return "(empty)";
  return str;
}

static std::string normalize_relative(const char *from)
{
  if (from[0] == '/')
    return string(from);

  char c[512];
  char *cwd = getcwd(c, sizeof(c));
  ostringstream oss;
  oss << cwd << "/" << from;
  return oss.str();
}

/* Complain about errors even without a logfile */
static void primitive_log(const std::string &str)
{
  std::cerr << str;
  std::cerr.flush();
  syslog(LOG_USER | LOG_NOTICE, "%s", str.c_str());
}

static inline bool prio_is_visible_on_stderr(int prio)
{
  return prio <= 15;
}

static inline int dout_prio_to_syslog_prio(int prio)
{
  if (prio <= 3)
    return LOG_CRIT;
  if (prio <= 5)
    return LOG_ERR;
  if (prio <= 15)
    return LOG_WARNING;
  if (prio <= 30)
    return LOG_NOTICE;
  if (prio <= 40)
    return LOG_INFO;
  return LOG_DEBUG;
}

static int safe_write(int fd, const char *buf, signed int len)
{
  int res;

  assert(len != 0);
  while (1) {
    res = write(fd, buf, len);
    if (res < 0) {
      int err = errno;
      if (err != EINTR) {
	ostringstream oss;
	oss << __func__ << ": failed to write to fd " << fd << ": "
	    << cpp_strerror(err) << "\n";
	primitive_log(oss.str());
	return err;
      }
    }
    len -= res;
    buf += res;
    if (len <= 0)
      return 0;
  }
}

static std::string get_basename(const std::string &filename)
{
  size_t last_slash = filename.find_last_of("/");
  if (last_slash == std::string::npos)
    return filename;
  return filename.substr(last_slash + 1);
}

static std::string get_dirname(const std::string &filename)
{
  size_t last_slash = filename.find_last_of("/");
  if (last_slash == std::string::npos)
    return ".";
  if (last_slash == 0)
    return filename;
  return filename.substr(0, last_slash);
}

static int create_symlink(const string &oldpath, const string &newpath)
{
  while (1) {
    if (::symlink(oldpath.c_str(), newpath.c_str()) == 0)
      return 0;
    int err = errno;
    if (err == EEXIST) {
      // Handle EEXIST
      if (::unlink(newpath.c_str())) {
	err = errno;
	ostringstream oss;
	oss << __func__ << ": failed to remove '" << newpath << "': "
	    << cpp_strerror(err) << "\n";
	primitive_log(oss.str());
	return err;
      }
    }
    else {
      // Other errors
      ostringstream oss;
      oss << __func__ << ": failed to symlink(oldpath='" << oldpath
	  << "', newpath='" << newpath << "'): " << cpp_strerror(err) << "\n";
      primitive_log(oss.str());
      return err;
    }
  }
}

///////////////////////////// DoutStreambuf /////////////////////////////
template <typename charT, typename traits>
DoutStreambuf<charT, traits>::DoutStreambuf()
  : flags(0), ofd(-1)
{
  // Initialize get pointer to zero so that underflow is called on the first read.
  this->setg(0, 0, 0);

  // Initialize output_buffer
  _clear_output_buffer();
}

// This function is called when the output buffer is filled.
// In this function, the buffer should be written to wherever it should
// be written to (in this case, the streambuf object that this is controlling).
template <typename charT, typename traits>
typename DoutStreambuf<charT, traits>::int_type
DoutStreambuf<charT, traits>::overflow(DoutStreambuf<charT, traits>::int_type c)
{
  {
    // zero-terminate the buffer
    charT* end_ptr = this->pptr();
    *end_ptr++ = '\0';
    *end_ptr++ = '\0';
//    char buf[1000];
//    hex2str(obuf, end_ptr - obuf, buf, sizeof(buf));
//    printf("overflow buffer: '%s'\n", buf);
  }

  // Loop over all lines in the buffer.
  int prio = 100;
  charT* start = obuf;
  while (true) {
    char* end = strchrnul(start, '\n');
    if (start == end) {
      if (*start == '\0')
	break;
      // skip zero-length lines
      ++start;
      continue;
    }
    if (*start == '\1') {
      // Decode some control characters
      ++start;
      unsigned char tmp = *((unsigned char*)start);
      prio = tmp - 11;
      ++start;
    }
    *end = '\n';
    char next = *(end+1);
    *(end+1) = '\0';

    // Now 'start' points to a NULL-terminated string, which we want to
    // output with priority 'prio'
    int len = strlen(start);
    if (flags & DOUTSB_FLAG_SYSLOG) {
      //printf("syslogging: '%s' len=%d\n", start, len);
      syslog(LOG_USER | dout_prio_to_syslog_prio(prio), "%s", start);
    }
    if (flags & DOUTSB_FLAG_STDOUT) {
      // Just write directly out to the stdout fileno. There's no point in
      // using something like fputs to write to a temporary buffer,
      // because we would just have to flush that temporary buffer
      // immediately.
      if (safe_write(STDOUT_FILENO, start, len))
	flags &= ~DOUTSB_FLAG_STDOUT;
    }
    if (flags & DOUTSB_FLAG_STDERR) {
      // Only write to stderr if the message is important enough.
      if (prio_is_visible_on_stderr(prio)) {
	if (safe_write(STDERR_FILENO, start, len))
	  flags &= ~DOUTSB_FLAG_STDERR;
      }
    }
    if (flags & DOUTSB_FLAG_OFILE) {
      if (safe_write(ofd, start, len))
	flags &= ~DOUTSB_FLAG_OFILE;
    }

    *(end+1) = next;
    start = end + 1;
  }

  _clear_output_buffer();

  // A value different than EOF (or traits::eof() for other traits) signals success.
  // If the function fails, either EOF (or traits::eof() for other traits) is returned or an
  // exception is thrown.
  return traits_ty::not_eof(c);
}

template <typename charT, typename traits>
void DoutStreambuf<charT, traits>::set_use_stderr(bool val)
{
  _dout_lock.Lock();
  use_stderr = val;
  if (val)
    flags |= DOUTSB_FLAG_STDERR;
  else
    flags &= ~DOUTSB_FLAG_STDERR;
  _dout_lock.Unlock();
}

template <typename charT, typename traits>
void DoutStreambuf<charT, traits>::read_global_config()
{
  assert(_dout_lock.is_locked());
  flags = 0;

  if (g_conf.log_to_syslog) {
    flags |= DOUTSB_FLAG_SYSLOG;
  }
  if (g_conf.log_to_stdout) {
    flags |= DOUTSB_FLAG_STDOUT;
  }
  if (use_stderr) {
    flags |= DOUTSB_FLAG_STDERR;
  }
  if (g_conf.log_to_file) {
    if (_read_ofile_config()) {
      flags |= DOUTSB_FLAG_OFILE;
    }
  }
}

template <typename charT, typename traits>
void DoutStreambuf<charT, traits>::
set_flags(int flags_)
{
  assert(_dout_lock.is_locked());
  flags = flags_;
}

template <typename charT, typename traits>
void DoutStreambuf<charT, traits>::
set_prio(int prio)
{
  charT* p = this->pptr();
  *p++ = '\1';
  unsigned char val = (prio + 11);
  *p++ = val;
  this->pbump(2);
}

// call after calling daemon()
template <typename charT, typename traits>
int DoutStreambuf<charT, traits>::rename_output_file()
{
  Mutex::Locker l(_dout_lock);
  if (!(flags & DOUTSB_FLAG_OFILE))
    return 0;

  string new_opath(_calculate_opath());
  if (opath == new_opath)
    return 0;

  int ret = ::rename(opath.c_str(), new_opath.c_str());
  if (ret) {
    int err = errno;
    ostringstream oss;
    oss << __func__ << ": failed to rename '" << opath << "' to "
        << "'" << new_opath << "': " << cpp_strerror(err) << "\n";
    primitive_log(oss.str());
    return err;
  }

  opath = new_opath;

//  // $type.$id symlink
//  if (g_conf.log_per_instance && _dout_name_symlink_path[0])
//    create_symlink(_dout_name_symlink_path);
//  if (_dout_rank_symlink_path[0])
//    create_symlink(_dout_rank_symlink_path);

  return 0;
}

template <typename charT, typename traits>
std::string DoutStreambuf<charT, traits>::config_to_str() const
{
  assert(_dout_lock.is_locked());
  ostringstream oss;
  oss << "g_conf.log_to_syslog = " << g_conf.log_to_syslog << "\n";
  oss << "g_conf.log_to_stdout = " << g_conf.log_to_stdout << "\n";
  oss << "use_stderr = " << use_stderr << "\n";
  oss << "g_conf.log_to_file = " << g_conf.log_to_file << "\n";
  oss << "g_conf.log_file = '" << cpp_str(g_conf.log_file) << "'\n";
  oss << "flags = 0x" << std::hex << flags << std::dec << "\n";
  oss << "ofd = " << ofd << "\n";
  oss << "opath = '" << opath << "'\n";
  return oss.str();
}

// This is called to flush the buffer.
// This is called when we're done with the file stream (or when .flush() is called).
template <typename charT, typename traits>
typename DoutStreambuf<charT, traits>::int_type
DoutStreambuf<charT, traits>::sync()
{
  //std::cout << "flush!" << std::endl;
  typename DoutStreambuf<charT, traits>::int_type
    ret(this->overflow(traits_ty::eof()));
  if (ret == traits_ty::eof())
    return -1;

  return 0;
}

template <typename charT, typename traits>
typename DoutStreambuf<charT, traits>::int_type
DoutStreambuf<charT, traits>::underflow()
{
  // We can't read from this
  // TODO: some more elegant way of preventing callers from trying to get input from this stream
  assert(0);
}

template <typename charT, typename traits>
void DoutStreambuf<charT, traits>::_clear_output_buffer()
{
  // Set up the put pointer.
  // Overflow is called when this buffer is filled
  this->setp(obuf, obuf + OBUF_SZ - 5);
}

template <typename charT, typename traits>
std::string DoutStreambuf<charT, traits>::_calculate_opath() const
{
  assert(_dout_lock.is_locked());
  if (!empty(g_conf.log_file)) {
    return normalize_relative(g_conf.log_file);
  }

  if (g_conf.log_per_instance) {
    char hostname[255];
    memset(hostname, 0, sizeof(hostname));
    int ret = gethostname(hostname, sizeof(hostname));
    if (ret) {
      int err = errno;
      ostringstream oss;
      oss << __func__ << ": error calling gethostname: " << cpp_strerror(err) << "\n";
      primitive_log(oss.str());
      return "";
    }
    ostringstream oss;
    oss << hostname << "." << getpid();
    return oss.str();
  }
  else {
    ostringstream oss;
    oss << g_conf.type << "." << g_conf.id << ".log";
    return oss.str();
  }
}

template <typename charT, typename traits>
bool DoutStreambuf<charT, traits>::_read_ofile_config()
{
  opath = _calculate_opath();
  if (opath.empty()) {
    ostringstream oss;
    oss << __func__ << ": _calculate_opath failed.\n";
    primitive_log(oss.str());
    return false;
  }

  assert(ofd == -1);
  ofd = open(opath.c_str(),
	    O_CREAT | O_WRONLY | O_CLOEXEC | O_APPEND, S_IWUSR | S_IRUSR);
  if (ofd < 0) {
    int err = errno;
    ostringstream oss;
    oss << "failed to open log file '" << opath << "': "
	<< cpp_strerror(err) << "\n";
    primitive_log(oss.str());
    return false;
  }

  return true;
}

// Explicit template instantiation
template class DoutStreambuf <char>;
<commit_msg>logging: create_symlink:sometimes use rel symlinks<commit_after>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2010 Dreamhost
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

#include "config.h"
#include "common/DoutStreambuf.h"
#include "common/errno.h"
#include "common/Mutex.h"

#include <assert.h>
#include <errno.h>
#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>
#include <streambuf>
#include <string.h>
#include <syslog.h>

///////////////////////////// Globals /////////////////////////////
// TODO: get rid of this lock using thread-local storage
extern Mutex _dout_lock;

/* True if we should output high-priority messages to stderr */
static bool use_stderr = true;

//////////////////////// Helper functions //////////////////////////
static bool empty(const char *str)
{
  if (!str)
    return true;
  if (!str[0])
    return true;
  return false;
}

static string cpp_str(const char *str)
{
  if (!str)
    return "(NULL)";
  if (str[0] == '\0')
    return "(empty)";
  return str;
}

static std::string normalize_relative(const char *from)
{
  if (from[0] == '/')
    return string(from);

  char c[512];
  char *cwd = getcwd(c, sizeof(c));
  ostringstream oss;
  oss << cwd << "/" << from;
  return oss.str();
}

/* Complain about errors even without a logfile */
static void primitive_log(const std::string &str)
{
  std::cerr << str;
  std::cerr.flush();
  syslog(LOG_USER | LOG_NOTICE, "%s", str.c_str());
}

static inline bool prio_is_visible_on_stderr(int prio)
{
  return prio <= 15;
}

static inline int dout_prio_to_syslog_prio(int prio)
{
  if (prio <= 3)
    return LOG_CRIT;
  if (prio <= 5)
    return LOG_ERR;
  if (prio <= 15)
    return LOG_WARNING;
  if (prio <= 30)
    return LOG_NOTICE;
  if (prio <= 40)
    return LOG_INFO;
  return LOG_DEBUG;
}

static int safe_write(int fd, const char *buf, signed int len)
{
  int res;

  assert(len != 0);
  while (1) {
    res = write(fd, buf, len);
    if (res < 0) {
      int err = errno;
      if (err != EINTR) {
	ostringstream oss;
	oss << __func__ << ": failed to write to fd " << fd << ": "
	    << cpp_strerror(err) << "\n";
	primitive_log(oss.str());
	return err;
      }
    }
    len -= res;
    buf += res;
    if (len <= 0)
      return 0;
  }
}

static std::string get_basename(const std::string &filename)
{
  size_t last_slash = filename.find_last_of("/");
  if (last_slash == std::string::npos)
    return filename;
  return filename.substr(last_slash + 1);
}

static std::string get_dirname(const std::string &filename)
{
  size_t last_slash = filename.find_last_of("/");
  if (last_slash == std::string::npos)
    return ".";
  if (last_slash == 0)
    return filename;
  return filename.substr(0, last_slash);
}

static int create_symlink(string oldpath, const string &newpath)
{
  // Create relative symlink if the files are in the same directory
  if (get_dirname(oldpath) == get_dirname(newpath)) {
    oldpath = string("./") + get_basename(oldpath);
    cerr << "setting oldpath = '" << oldpath << "'" << std::endl;
  }

  while (1) {
    if (::symlink(oldpath.c_str(), newpath.c_str()) == 0)
      return 0;
    int err = errno;
    if (err == EEXIST) {
      // Handle EEXIST
      if (::unlink(newpath.c_str())) {
	err = errno;
	ostringstream oss;
	oss << __func__ << ": failed to remove '" << newpath << "': "
	    << cpp_strerror(err) << "\n";
	primitive_log(oss.str());
	return err;
      }
    }
    else {
      // Other errors
      ostringstream oss;
      oss << __func__ << ": failed to symlink(oldpath='" << oldpath
	  << "', newpath='" << newpath << "'): " << cpp_strerror(err) << "\n";
      primitive_log(oss.str());
      return err;
    }
  }
}

///////////////////////////// DoutStreambuf /////////////////////////////
template <typename charT, typename traits>
DoutStreambuf<charT, traits>::DoutStreambuf()
  : flags(0), ofd(-1)
{
  // Initialize get pointer to zero so that underflow is called on the first read.
  this->setg(0, 0, 0);

  // Initialize output_buffer
  _clear_output_buffer();
}

// This function is called when the output buffer is filled.
// In this function, the buffer should be written to wherever it should
// be written to (in this case, the streambuf object that this is controlling).
template <typename charT, typename traits>
typename DoutStreambuf<charT, traits>::int_type
DoutStreambuf<charT, traits>::overflow(DoutStreambuf<charT, traits>::int_type c)
{
  {
    // zero-terminate the buffer
    charT* end_ptr = this->pptr();
    *end_ptr++ = '\0';
    *end_ptr++ = '\0';
//    char buf[1000];
//    hex2str(obuf, end_ptr - obuf, buf, sizeof(buf));
//    printf("overflow buffer: '%s'\n", buf);
  }

  // Loop over all lines in the buffer.
  int prio = 100;
  charT* start = obuf;
  while (true) {
    char* end = strchrnul(start, '\n');
    if (start == end) {
      if (*start == '\0')
	break;
      // skip zero-length lines
      ++start;
      continue;
    }
    if (*start == '\1') {
      // Decode some control characters
      ++start;
      unsigned char tmp = *((unsigned char*)start);
      prio = tmp - 11;
      ++start;
    }
    *end = '\n';
    char next = *(end+1);
    *(end+1) = '\0';

    // Now 'start' points to a NULL-terminated string, which we want to
    // output with priority 'prio'
    int len = strlen(start);
    if (flags & DOUTSB_FLAG_SYSLOG) {
      //printf("syslogging: '%s' len=%d\n", start, len);
      syslog(LOG_USER | dout_prio_to_syslog_prio(prio), "%s", start);
    }
    if (flags & DOUTSB_FLAG_STDOUT) {
      // Just write directly out to the stdout fileno. There's no point in
      // using something like fputs to write to a temporary buffer,
      // because we would just have to flush that temporary buffer
      // immediately.
      if (safe_write(STDOUT_FILENO, start, len))
	flags &= ~DOUTSB_FLAG_STDOUT;
    }
    if (flags & DOUTSB_FLAG_STDERR) {
      // Only write to stderr if the message is important enough.
      if (prio_is_visible_on_stderr(prio)) {
	if (safe_write(STDERR_FILENO, start, len))
	  flags &= ~DOUTSB_FLAG_STDERR;
      }
    }
    if (flags & DOUTSB_FLAG_OFILE) {
      if (safe_write(ofd, start, len))
	flags &= ~DOUTSB_FLAG_OFILE;
    }

    *(end+1) = next;
    start = end + 1;
  }

  _clear_output_buffer();

  // A value different than EOF (or traits::eof() for other traits) signals success.
  // If the function fails, either EOF (or traits::eof() for other traits) is returned or an
  // exception is thrown.
  return traits_ty::not_eof(c);
}

template <typename charT, typename traits>
void DoutStreambuf<charT, traits>::set_use_stderr(bool val)
{
  _dout_lock.Lock();
  use_stderr = val;
  if (val)
    flags |= DOUTSB_FLAG_STDERR;
  else
    flags &= ~DOUTSB_FLAG_STDERR;
  _dout_lock.Unlock();
}

template <typename charT, typename traits>
void DoutStreambuf<charT, traits>::read_global_config()
{
  assert(_dout_lock.is_locked());
  flags = 0;

  if (g_conf.log_to_syslog) {
    flags |= DOUTSB_FLAG_SYSLOG;
  }
  if (g_conf.log_to_stdout) {
    flags |= DOUTSB_FLAG_STDOUT;
  }
  if (use_stderr) {
    flags |= DOUTSB_FLAG_STDERR;
  }
  if (g_conf.log_to_file) {
    if (_read_ofile_config()) {
      flags |= DOUTSB_FLAG_OFILE;
    }
  }
}

template <typename charT, typename traits>
void DoutStreambuf<charT, traits>::
set_flags(int flags_)
{
  assert(_dout_lock.is_locked());
  flags = flags_;
}

template <typename charT, typename traits>
void DoutStreambuf<charT, traits>::
set_prio(int prio)
{
  charT* p = this->pptr();
  *p++ = '\1';
  unsigned char val = (prio + 11);
  *p++ = val;
  this->pbump(2);
}

// call after calling daemon()
template <typename charT, typename traits>
int DoutStreambuf<charT, traits>::rename_output_file()
{
  Mutex::Locker l(_dout_lock);
  if (!(flags & DOUTSB_FLAG_OFILE))
    return 0;

  string new_opath(_calculate_opath());
  if (opath == new_opath)
    return 0;

  int ret = ::rename(opath.c_str(), new_opath.c_str());
  if (ret) {
    int err = errno;
    ostringstream oss;
    oss << __func__ << ": failed to rename '" << opath << "' to "
        << "'" << new_opath << "': " << cpp_strerror(err) << "\n";
    primitive_log(oss.str());
    return err;
  }

  opath = new_opath;

//  // $type.$id symlink
//  if (g_conf.log_per_instance && _dout_name_symlink_path[0])
//    create_symlink(_dout_name_symlink_path);
//  if (_dout_rank_symlink_path[0])
//    create_symlink(_dout_rank_symlink_path);

  return 0;
}

template <typename charT, typename traits>
std::string DoutStreambuf<charT, traits>::config_to_str() const
{
  assert(_dout_lock.is_locked());
  ostringstream oss;
  oss << "g_conf.log_to_syslog = " << g_conf.log_to_syslog << "\n";
  oss << "g_conf.log_to_stdout = " << g_conf.log_to_stdout << "\n";
  oss << "use_stderr = " << use_stderr << "\n";
  oss << "g_conf.log_to_file = " << g_conf.log_to_file << "\n";
  oss << "g_conf.log_file = '" << cpp_str(g_conf.log_file) << "'\n";
  oss << "flags = 0x" << std::hex << flags << std::dec << "\n";
  oss << "ofd = " << ofd << "\n";
  oss << "opath = '" << opath << "'\n";
  return oss.str();
}

// This is called to flush the buffer.
// This is called when we're done with the file stream (or when .flush() is called).
template <typename charT, typename traits>
typename DoutStreambuf<charT, traits>::int_type
DoutStreambuf<charT, traits>::sync()
{
  //std::cout << "flush!" << std::endl;
  typename DoutStreambuf<charT, traits>::int_type
    ret(this->overflow(traits_ty::eof()));
  if (ret == traits_ty::eof())
    return -1;

  return 0;
}

template <typename charT, typename traits>
typename DoutStreambuf<charT, traits>::int_type
DoutStreambuf<charT, traits>::underflow()
{
  // We can't read from this
  // TODO: some more elegant way of preventing callers from trying to get input from this stream
  assert(0);
}

template <typename charT, typename traits>
void DoutStreambuf<charT, traits>::_clear_output_buffer()
{
  // Set up the put pointer.
  // Overflow is called when this buffer is filled
  this->setp(obuf, obuf + OBUF_SZ - 5);
}

template <typename charT, typename traits>
std::string DoutStreambuf<charT, traits>::_calculate_opath() const
{
  assert(_dout_lock.is_locked());
  if (!empty(g_conf.log_file)) {
    return normalize_relative(g_conf.log_file);
  }

  if (g_conf.log_per_instance) {
    char hostname[255];
    memset(hostname, 0, sizeof(hostname));
    int ret = gethostname(hostname, sizeof(hostname));
    if (ret) {
      int err = errno;
      ostringstream oss;
      oss << __func__ << ": error calling gethostname: " << cpp_strerror(err) << "\n";
      primitive_log(oss.str());
      return "";
    }
    ostringstream oss;
    oss << hostname << "." << getpid();
    return oss.str();
  }
  else {
    ostringstream oss;
    oss << g_conf.type << "." << g_conf.id << ".log";
    return oss.str();
  }
}

template <typename charT, typename traits>
bool DoutStreambuf<charT, traits>::_read_ofile_config()
{
  opath = _calculate_opath();
  if (opath.empty()) {
    ostringstream oss;
    oss << __func__ << ": _calculate_opath failed.\n";
    primitive_log(oss.str());
    return false;
  }

  assert(ofd == -1);
  ofd = open(opath.c_str(),
	    O_CREAT | O_WRONLY | O_CLOEXEC | O_APPEND, S_IWUSR | S_IRUSR);
  if (ofd < 0) {
    int err = errno;
    ostringstream oss;
    oss << "failed to open log file '" << opath << "': "
	<< cpp_strerror(err) << "\n";
    primitive_log(oss.str());
    return false;
  }

  return true;
}

// Explicit template instantiation
template class DoutStreambuf <char>;
<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// class for TOF reconstruction                                              //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include <cstdlib>
#include "TObjArray.h"
#include "TString.h"

#include "AliLog.h"
#include "AliRawReader.h"

#include "AliTOFClusterFinder.h"
#include "AliTOFClusterFinderV1.h"
#include "AliTOFcalib.h"
#include "AliTOFtrackerMI.h"
#include "AliTOFtracker.h"
#include "AliTOFtrackerV1.h"
#include "AliTOFReconstructor.h"

class TTree;

class AliESDEvent;

ClassImp(AliTOFReconstructor)

 //____________________________________________________________________
AliTOFReconstructor::AliTOFReconstructor()
  : AliReconstructor(),
    fTOFcalib(0)
{
//
// ctor
//

  //Retrieving the TOF calibration info
  fTOFcalib    = new AliTOFcalib();
  fTOFcalib->CreateCalObjects();

  if(!fTOFcalib->ReadParOnlineDelayFromCDB("TOF/Calib",-1)) {AliFatal("Exiting, no CDB object found!!!");exit(0);}
  if(!fTOFcalib->ReadParOnlineStatusFromCDB("TOF/Calib",-1)) {AliFatal("Exiting, no CDB object found!!!");exit(0);}

  if(!fTOFcalib->ReadParOfflineFromCDB("TOF/Calib",-1)) {AliFatal("Exiting, no CDB object found!!!");exit(0);}
}

//_____________________________________________________________________________
AliTOFReconstructor::~AliTOFReconstructor()
{
//
// dtor
//
  delete fTOFcalib;
}

//_____________________________________________________________________________
void AliTOFReconstructor::Reconstruct(AliRawReader *rawReader,
                                      TTree *clustersTree) const
{
  //
  // reconstruct clusters from Raw Data
  //

  TString optionString = GetOption();
  // use V1 cluster finder if selected
  if (optionString.Contains("ClusterizerV1")) {
    static AliTOFClusterFinderV1 tofClus(fTOFcalib);

    // decoder version option
    if (optionString.Contains("DecoderV1"))
      tofClus.SetDecoderVersion(1);
    else
      tofClus.SetDecoderVersion(0);

    tofClus.Digits2RecPoints(rawReader, clustersTree);
  }
  else {
    static AliTOFClusterFinder tofClus(fTOFcalib);

    // decoder version option
    if (optionString.Contains("DecoderV1"))
      tofClus.SetDecoderVersion(1);
    else
      tofClus.SetDecoderVersion(0);

    tofClus.Digits2RecPoints(rawReader, clustersTree);
  }

}

//_____________________________________________________________________________
void AliTOFReconstructor::Reconstruct(TTree *digitsTree,
                                      TTree *clustersTree) const
{
  //
  // reconstruct clusters from digits
  //

  AliDebug(2,Form("Global Event loop mode: Creating Recpoints from Digits Tree"));

  TString optionString = GetOption();
  // use V1 cluster finder if selected
  if (optionString.Contains("ClusterizerV1")) {
    static AliTOFClusterFinderV1 tofClus(fTOFcalib);

    // decoder version option
    if (optionString.Contains("DecoderV1"))
      tofClus.SetDecoderVersion(1);
    else
      tofClus.SetDecoderVersion(0);

    tofClus.Digits2RecPoints(digitsTree, clustersTree);
  }
  else {
    static AliTOFClusterFinder tofClus(fTOFcalib);

    // decoder version option
    if (optionString.Contains("DecoderV1"))
      tofClus.SetDecoderVersion(1);
    else
      tofClus.SetDecoderVersion(0);

    tofClus.Digits2RecPoints(digitsTree, clustersTree);
  }

}
//_____________________________________________________________________________
  void AliTOFReconstructor::ConvertDigits(AliRawReader* reader, TTree* digitsTree) const
{
// reconstruct clusters from digits

  AliDebug(2,Form("Global Event loop mode: Converting Raw Data to a Digits Tree"));

  TString optionString = GetOption();
  // use V1 cluster finder if selected
  if (optionString.Contains("ClusterizerV1")) {
    static AliTOFClusterFinderV1 tofClus(fTOFcalib);

    // decoder version option
    if (optionString.Contains("DecoderV1"))
      tofClus.SetDecoderVersion(1);
    else
      tofClus.SetDecoderVersion(0);

    tofClus.Raw2Digits(reader, digitsTree);
  }
  else {
    static AliTOFClusterFinder tofClus(fTOFcalib);

    // decoder version option
    if (optionString.Contains("DecoderV1"))
      tofClus.SetDecoderVersion(1);
    else
      tofClus.SetDecoderVersion(0);

    tofClus.Raw2Digits(reader, digitsTree);
  }

}

//_____________________________________________________________________________
AliTracker* AliTOFReconstructor::CreateTracker() const
{

  //
  // create a TOF tracker using
  // TOF Reco Param collected by STEER
  //

  TString selectedTracker = GetOption();

  AliTracker *tracker;
  // use MI tracker if selected
  if (selectedTracker.Contains("TrackerMI")) {
    tracker = new AliTOFtrackerMI();
  }
  // use V1 tracker if selected
  else if (selectedTracker.Contains("TrackerV1")) {
    tracker =  new AliTOFtrackerV1();
  }
  else {
    tracker = new AliTOFtracker();
  }
  return tracker;

}
<commit_msg>Switching of the decoder version used in reconstruction<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id$ */

///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// class for TOF reconstruction                                              //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include <cstdlib>
#include "TObjArray.h"
#include "TString.h"

#include "AliLog.h"
#include "AliRawReader.h"

#include "AliTOFClusterFinder.h"
#include "AliTOFClusterFinderV1.h"
#include "AliTOFcalib.h"
#include "AliTOFtrackerMI.h"
#include "AliTOFtracker.h"
#include "AliTOFtrackerV1.h"
#include "AliTOFReconstructor.h"

class TTree;

class AliESDEvent;

ClassImp(AliTOFReconstructor)

 //____________________________________________________________________
AliTOFReconstructor::AliTOFReconstructor()
  : AliReconstructor(),
    fTOFcalib(0)
{
//
// ctor
//

  //Retrieving the TOF calibration info
  fTOFcalib    = new AliTOFcalib();
  fTOFcalib->CreateCalObjects();

  if(!fTOFcalib->ReadParOnlineDelayFromCDB("TOF/Calib",-1)) {AliFatal("Exiting, no CDB object found!!!");exit(0);}
  if(!fTOFcalib->ReadParOnlineStatusFromCDB("TOF/Calib",-1)) {AliFatal("Exiting, no CDB object found!!!");exit(0);}

  if(!fTOFcalib->ReadParOfflineFromCDB("TOF/Calib",-1)) {AliFatal("Exiting, no CDB object found!!!");exit(0);}
}

//_____________________________________________________________________________
AliTOFReconstructor::~AliTOFReconstructor()
{
//
// dtor
//
  delete fTOFcalib;
}

//_____________________________________________________________________________
void AliTOFReconstructor::Reconstruct(AliRawReader *rawReader,
                                      TTree *clustersTree) const
{
  //
  // reconstruct clusters from Raw Data
  //

  TString optionString = GetOption();
  // use V1 cluster finder if selected
  if (optionString.Contains("ClusterizerV1")) {
    static AliTOFClusterFinderV1 tofClus(fTOFcalib);

    // decoder version option
    if (optionString.Contains("DecoderV0"))
      tofClus.SetDecoderVersion(0);
    else
      tofClus.SetDecoderVersion(1);

    tofClus.Digits2RecPoints(rawReader, clustersTree);
  }
  else {
    static AliTOFClusterFinder tofClus(fTOFcalib);

    // decoder version option
    if (optionString.Contains("DecoderV0"))
      tofClus.SetDecoderVersion(0);
    else
      tofClus.SetDecoderVersion(1);

    tofClus.Digits2RecPoints(rawReader, clustersTree);
  }

}

//_____________________________________________________________________________
void AliTOFReconstructor::Reconstruct(TTree *digitsTree,
                                      TTree *clustersTree) const
{
  //
  // reconstruct clusters from digits
  //

  AliDebug(2,Form("Global Event loop mode: Creating Recpoints from Digits Tree"));

  TString optionString = GetOption();
  // use V1 cluster finder if selected
  if (optionString.Contains("ClusterizerV1")) {
    static AliTOFClusterFinderV1 tofClus(fTOFcalib);

    // decoder version option
    if (optionString.Contains("DecoderV0"))
      tofClus.SetDecoderVersion(0);
    else
      tofClus.SetDecoderVersion(1);

    tofClus.Digits2RecPoints(digitsTree, clustersTree);
  }
  else {
    static AliTOFClusterFinder tofClus(fTOFcalib);

    // decoder version option
    if (optionString.Contains("DecoderV0"))
      tofClus.SetDecoderVersion(0);
    else
      tofClus.SetDecoderVersion(1);

    tofClus.Digits2RecPoints(digitsTree, clustersTree);
  }

}
//_____________________________________________________________________________
  void AliTOFReconstructor::ConvertDigits(AliRawReader* reader, TTree* digitsTree) const
{
// reconstruct clusters from digits

  AliDebug(2,Form("Global Event loop mode: Converting Raw Data to a Digits Tree"));

  TString optionString = GetOption();
  // use V1 cluster finder if selected
  if (optionString.Contains("ClusterizerV1")) {
    static AliTOFClusterFinderV1 tofClus(fTOFcalib);

    // decoder version option
    if (optionString.Contains("DecoderV0"))
      tofClus.SetDecoderVersion(0);
    else
      tofClus.SetDecoderVersion(1);

    tofClus.Raw2Digits(reader, digitsTree);
  }
  else {
    static AliTOFClusterFinder tofClus(fTOFcalib);

    // decoder version option
    if (optionString.Contains("DecoderV0"))
      tofClus.SetDecoderVersion(0);
    else
      tofClus.SetDecoderVersion(1);

    tofClus.Raw2Digits(reader, digitsTree);
  }

}

//_____________________________________________________________________________
AliTracker* AliTOFReconstructor::CreateTracker() const
{

  //
  // create a TOF tracker using
  // TOF Reco Param collected by STEER
  //

  TString selectedTracker = GetOption();

  AliTracker *tracker;
  // use MI tracker if selected
  if (selectedTracker.Contains("TrackerMI")) {
    tracker = new AliTOFtrackerMI();
  }
  // use V1 tracker if selected
  else if (selectedTracker.Contains("TrackerV1")) {
    tracker =  new AliTOFtrackerV1();
  }
  else {
    tracker = new AliTOFtracker();
  }
  return tracker;

}
<|endoftext|>


<commit_before>// Copyright 2020 The TensorFlow Runtime Authors
//
// 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.

// This file implements the tfrt_gpu.blas kernels.
#include <cstdint>

#include "llvm/Support/Errc.h"
#include "tfrt/gpu/gpu_types.h"
#include "tfrt/gpu/kernels/kernels_detail.h"
#include "tfrt/gpu/wrapper/blas_wrapper.h"
#include "tfrt/gpu/wrapper/cublas_wrapper.h"
#include "tfrt/gpu/wrapper/rocblas_wrapper.h"
#include "tfrt/gpu/wrapper/wrapper.h"
#include "tfrt/host_context/kernel_registry.h"
#include "tfrt/support/fp16.h"

namespace tfrt {
namespace gpu {

static Expected<GpuBlasHandle> BlasCreate(Argument<GpuStream> stream) {
  auto current = wrapper::CtxSetCurrent(stream->context()->get());
  if (!current) return current.takeError();
  auto handle = wrapper::BlasCreate(*current);
  if (!handle) return handle.takeError();
  if (auto error = wrapper::BlasSetStream(handle->get(), stream->get()))
    return std::move(error);
  return GpuBlasHandle(stream.ValueRef(), std::move(*handle));
}

template <typename T>
static llvm::Expected<wrapper::Pointer<void>> GetScalePointer(
    AsyncValue* value, mlir::TypeID typeId, wrapper::Platform platform) {
  if (mlir::TypeID::get<T>() != typeId)
    return MakeStringError("unexpected argument type");
  return wrapper::Pointer<void>(&value->get<T>(), platform);
}

static llvm::Expected<wrapper::Pointer<void>> GetScalePointer(
    AsyncValue* value, mlir::TypeID typeId, wrapper::Platform platform) {
  if (value->IsType<fp16>())
    return GetScalePointer<fp16>(value, typeId, platform);
  if (value->IsType<float>())
    return GetScalePointer<float>(value, typeId, platform);
  if (value->IsType<double>()) {
    return GetScalePointer<double>(value, typeId, platform);
  }
  return MakeStringError("pointer type not supported");
}

static llvm::Expected<wrapper::Pointer<void>> GetScalePointer(
    AsyncValue* value, wrapper::BlasDataType data_type) {
  auto type_id = wrapper::GetBlasDataTypeId(data_type);
  return GetScalePointer(value, type_id, data_type.platform());
}

static llvm::Expected<wrapper::Pointer<void>> GetScalePointer(
    AsyncValue* value, wrapper::BlasComputeType compute_type) {
  auto type_id = wrapper::GetBlasComputeTypeId(compute_type);
  return GetScalePointer(value, type_id, compute_type.platform());
}

static Error BlasAxpy(const GpuBlasHandle& handle, int32_t n, AsyncValue* alpha,
                      const GpuBuffer& x, int32_t strideX, const GpuBuffer& y,
                      int32_t strideY, Attribute<int32_t> executionType,
                      Attribute<int32_t> typeAlpha, Attribute<int32_t> typeX,
                      Attribute<int32_t> typeY) {
  auto current = wrapper::CtxSetCurrent(handle.context()->get());
  if (!current) return current.takeError();

  auto type_alpha = wrapper::BlasDataType::FromOpaqueValue(*typeAlpha);
  auto alpha_ptr = GetScalePointer(alpha, type_alpha);
  if (!alpha_ptr) return alpha_ptr.takeError();

  return wrapper::BlasAxpyEx(
      *current, handle.get(), n, *alpha_ptr, type_alpha, x.pointer(),
      wrapper::BlasDataType::FromOpaqueValue(*typeX), strideX, y.pointer(),
      wrapper::BlasDataType::FromOpaqueValue(*typeY), strideY,
      wrapper::BlasDataType::FromOpaqueValue(*executionType));
}

static wrapper::BlasGemmAlgo BlasGemmAlgo(Attribute<int32_t> algo) {
  return wrapper::BlasGemmAlgo::FromOpaqueValue(*algo);
}

static Error BlasGemm(const GpuBlasHandle& handle, int32_t m, int32_t n,
                      int32_t k, AsyncValue* alpha, const GpuBuffer& A,
                      int32_t heightA, const GpuBuffer& B, int32_t heightB,
                      AsyncValue* beta, const GpuBuffer& C, int32_t heightC,
                      wrapper::BlasGemmAlgo algo,
                      // Needs to be sorted alphabetically by attribute name!
                      Attribute<int32_t> computeType, Attribute<int32_t> transA,
                      Attribute<int32_t> transB, Attribute<int32_t> typeA,
                      Attribute<int32_t> typeB, Attribute<int32_t> typeC) {
  auto current = wrapper::CtxSetCurrent(handle.context()->get());
  if (!current) return current.takeError();

  auto compute_type = wrapper::BlasComputeType::FromOpaqueValue(*computeType);
  auto alpha_ptr = GetScalePointer(alpha, compute_type);
  if (!alpha_ptr) return alpha_ptr.takeError();
  auto beta_ptr = GetScalePointer(beta, compute_type);
  if (!beta_ptr) return beta_ptr.takeError();

  return wrapper::BlasGemmEx(
      *current, handle.get(), wrapper::BlasOperation::FromOpaqueValue(*transA),
      wrapper::BlasOperation::FromOpaqueValue(*transB), m, n, k, *alpha_ptr,
      A.pointer(), wrapper::BlasDataType::FromOpaqueValue(*typeA), heightA,
      B.pointer(), wrapper::BlasDataType::FromOpaqueValue(*typeB), heightB,
      *beta_ptr, C.pointer(), wrapper::BlasDataType::FromOpaqueValue(*typeC),
      heightC, compute_type, algo);
}

static Error BlasGemmBatch(
    const GpuBlasHandle& handle, int32_t m, int32_t n, int32_t k,
    AsyncValue* alpha, const GpuBuffer& A, int32_t heightA, int64_t strideA,
    const GpuBuffer& B, int32_t heightB, int64_t strideB, AsyncValue* beta,
    const GpuBuffer& C, int32_t heightC, int64_t strideC, int32_t batchCount,
    wrapper::BlasGemmAlgo algo,
    // Needs to be sorted alphabetically by attribute name!
    Attribute<int32_t> computeType, Attribute<int32_t> transA,
    Attribute<int32_t> transB, Attribute<int32_t> typeA,
    Attribute<int32_t> typeB, Attribute<int32_t> typeC) {
  auto current = wrapper::CtxSetCurrent(handle.context()->get());
  if (!current) return current.takeError();

  auto compute_type = wrapper::BlasComputeType::FromOpaqueValue(*computeType);
  auto alpha_ptr = GetScalePointer(alpha, compute_type);
  if (!alpha_ptr) return alpha_ptr.takeError();
  auto beta_ptr = GetScalePointer(beta, compute_type);
  if (!beta_ptr) return beta_ptr.takeError();

  return wrapper::BlasGemmStridedBatchedEx(
      *current, handle.get(), wrapper::BlasOperation::FromOpaqueValue(*transA),
      wrapper::BlasOperation::FromOpaqueValue(*transB), m, n, k, *alpha_ptr,
      A.pointer(), wrapper::BlasDataType::FromOpaqueValue(*typeA), heightA,
      strideA, B.pointer(), wrapper::BlasDataType::FromOpaqueValue(*typeB),
      heightB, strideB, *beta_ptr, C.pointer(),
      wrapper::BlasDataType::FromOpaqueValue(*typeC), heightC, strideC,
      batchCount, compute_type, algo);
}

static Error BlasTrsmBatch(
    const GpuBlasHandle& handle, int32_t m, int32_t n, AsyncValue* alpha,
    const GpuBuffer& A, int32_t heightA, const GpuBuffer& B, int32_t heightB,
    int32_t batchCount,
    // Needs to be sorted alphabetically by attribute name!
    Attribute<int32_t> dataType, Attribute<int32_t> diagType,
    Attribute<int32_t> fillMode, Attribute<int32_t> sideMode,
    Attribute<int32_t> trans) {
  // TODO(hanbinyoon): Also support the ROCm function corresponding to
  // cublas<t>trsmBatched.
  auto platform = handle->platform();
  if (platform != wrapper::Platform::CUDA)
    return MakeStringError("Unsupported platform ", platform);

  auto current = wrapper::CtxSetCurrent(handle.context()->get());
  if (!current) return current.takeError();

  cudaDataType data_type = wrapper::BlasDataType::FromOpaqueValue(*dataType);
  auto alpha_ptr = GetScalePointer(alpha, data_type);
  if (!alpha_ptr) return alpha_ptr.takeError();

  auto call = [&](auto dummy) {
    using T = decltype(dummy);
    auto pointer_array =
        handle.context()->AllocateHostPoolMemory<T*>(*current, 2 * batchCount);
    if (!pointer_array) return pointer_array.takeError();
    T** b_array = pointer_array->get().raw(platform);
    const T** a_array = const_cast<const T**>(b_array + batchCount);

    auto side_mode = wrapper::BlasSideMode::FromOpaqueValue(*sideMode);
    ptrdiff_t a_batch_stride = side_mode == CUBLAS_SIDE_LEFT ? m * m : n * n;
    ptrdiff_t b_batch_stride = m * n;
    const T* a_ptr = static_cast<const T*>(A.pointer().raw(platform));
    T* b_ptr = static_cast<T*>(A.pointer().raw(platform));
    for (int32_t i = 0; i < batchCount; ++i) {
      a_array[i] = a_ptr + i * a_batch_stride;
      b_array[i] = b_ptr + i * b_batch_stride;
    }

    wrapper::Pointer<const T*> a_array_ptr(a_array, platform);
    wrapper::Pointer<T*> b_array_ptr(b_array, platform);
    auto cast_alpha_ptr = static_cast<wrapper::Pointer<const T>>(*alpha_ptr);

    auto current = wrapper::CtxSetCurrent(handle.context()->get());
    if (!current) return current.takeError();

    return wrapper::CublasTrsmBatched(
        *current, handle.get(), side_mode,
        wrapper::BlasFillMode::FromOpaqueValue(*fillMode),
        wrapper::BlasOperation::FromOpaqueValue(*trans),
        wrapper::BlasDiagType::FromOpaqueValue(*diagType), m, n, cast_alpha_ptr,
        a_array_ptr, heightA, b_array_ptr, heightB, batchCount);
  };

  switch (data_type) {
    case CUDA_R_32F:
      return call(float{});
    case CUDA_R_64F:
      return call(double{});
    case CUDA_C_32F:
      return call(cuComplex{});
    case CUDA_C_64F:
      return call(cuDoubleComplex{});
    default:
      return MakeStringError("Unsupported data type ", data_type);
  }
}

void RegisterGpuBlasKernels(KernelRegistry* kernel_reg) {
  kernel_reg->AddKernel("tfrt_gpu.blas.create", TFRT_KERNEL(BlasCreate));
  kernel_reg->AddKernel("tfrt_gpu.blas.axpy",
                        TFRT_KERNEL_WITH_CHAIN_RESULT(BlasAxpy));
  kernel_reg->AddKernel("tfrt_gpu.blas.gemm.algo", TFRT_KERNEL(BlasGemmAlgo));
  kernel_reg->AddKernel("tfrt_gpu.blas.gemm",
                        TFRT_KERNEL_WITH_CHAIN_RESULT(BlasGemm));
  kernel_reg->AddKernel("tfrt_gpu.blas.gemm.batch",
                        TFRT_KERNEL_WITH_CHAIN_RESULT(BlasGemmBatch));
  kernel_reg->AddKernel("tfrt_gpu.blas.trsm.batch",
                        TFRT_KERNEL_WITH_CHAIN_RESULT(BlasTrsmBatch));
}
}  // namespace gpu
}  // namespace tfrt
<commit_msg>Minor fix to tfrt_gpu.blas.trsm.batch kernel.<commit_after>// Copyright 2020 The TensorFlow Runtime Authors
//
// 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.

// This file implements the tfrt_gpu.blas kernels.
#include <cstdint>

#include "llvm/Support/Errc.h"
#include "tfrt/gpu/gpu_types.h"
#include "tfrt/gpu/kernels/kernels_detail.h"
#include "tfrt/gpu/wrapper/blas_wrapper.h"
#include "tfrt/gpu/wrapper/cublas_wrapper.h"
#include "tfrt/gpu/wrapper/rocblas_wrapper.h"
#include "tfrt/gpu/wrapper/wrapper.h"
#include "tfrt/host_context/kernel_registry.h"
#include "tfrt/support/fp16.h"

namespace tfrt {
namespace gpu {

static Expected<GpuBlasHandle> BlasCreate(Argument<GpuStream> stream) {
  auto current = wrapper::CtxSetCurrent(stream->context()->get());
  if (!current) return current.takeError();
  auto handle = wrapper::BlasCreate(*current);
  if (!handle) return handle.takeError();
  if (auto error = wrapper::BlasSetStream(handle->get(), stream->get()))
    return std::move(error);
  return GpuBlasHandle(stream.ValueRef(), std::move(*handle));
}

template <typename T>
static llvm::Expected<wrapper::Pointer<void>> GetScalePointer(
    AsyncValue* value, mlir::TypeID typeId, wrapper::Platform platform) {
  if (mlir::TypeID::get<T>() != typeId)
    return MakeStringError("unexpected argument type");
  return wrapper::Pointer<void>(&value->get<T>(), platform);
}

static llvm::Expected<wrapper::Pointer<void>> GetScalePointer(
    AsyncValue* value, mlir::TypeID typeId, wrapper::Platform platform) {
  if (value->IsType<fp16>())
    return GetScalePointer<fp16>(value, typeId, platform);
  if (value->IsType<float>())
    return GetScalePointer<float>(value, typeId, platform);
  if (value->IsType<double>()) {
    return GetScalePointer<double>(value, typeId, platform);
  }
  return MakeStringError("pointer type not supported");
}

static llvm::Expected<wrapper::Pointer<void>> GetScalePointer(
    AsyncValue* value, wrapper::BlasDataType data_type) {
  auto type_id = wrapper::GetBlasDataTypeId(data_type);
  return GetScalePointer(value, type_id, data_type.platform());
}

static llvm::Expected<wrapper::Pointer<void>> GetScalePointer(
    AsyncValue* value, wrapper::BlasComputeType compute_type) {
  auto type_id = wrapper::GetBlasComputeTypeId(compute_type);
  return GetScalePointer(value, type_id, compute_type.platform());
}

static Error BlasAxpy(const GpuBlasHandle& handle, int32_t n, AsyncValue* alpha,
                      const GpuBuffer& x, int32_t strideX, const GpuBuffer& y,
                      int32_t strideY, Attribute<int32_t> executionType,
                      Attribute<int32_t> typeAlpha, Attribute<int32_t> typeX,
                      Attribute<int32_t> typeY) {
  auto current = wrapper::CtxSetCurrent(handle.context()->get());
  if (!current) return current.takeError();

  auto type_alpha = wrapper::BlasDataType::FromOpaqueValue(*typeAlpha);
  auto alpha_ptr = GetScalePointer(alpha, type_alpha);
  if (!alpha_ptr) return alpha_ptr.takeError();

  return wrapper::BlasAxpyEx(
      *current, handle.get(), n, *alpha_ptr, type_alpha, x.pointer(),
      wrapper::BlasDataType::FromOpaqueValue(*typeX), strideX, y.pointer(),
      wrapper::BlasDataType::FromOpaqueValue(*typeY), strideY,
      wrapper::BlasDataType::FromOpaqueValue(*executionType));
}

static wrapper::BlasGemmAlgo BlasGemmAlgo(Attribute<int32_t> algo) {
  return wrapper::BlasGemmAlgo::FromOpaqueValue(*algo);
}

static Error BlasGemm(const GpuBlasHandle& handle, int32_t m, int32_t n,
                      int32_t k, AsyncValue* alpha, const GpuBuffer& A,
                      int32_t heightA, const GpuBuffer& B, int32_t heightB,
                      AsyncValue* beta, const GpuBuffer& C, int32_t heightC,
                      wrapper::BlasGemmAlgo algo,
                      // Needs to be sorted alphabetically by attribute name!
                      Attribute<int32_t> computeType, Attribute<int32_t> transA,
                      Attribute<int32_t> transB, Attribute<int32_t> typeA,
                      Attribute<int32_t> typeB, Attribute<int32_t> typeC) {
  auto current = wrapper::CtxSetCurrent(handle.context()->get());
  if (!current) return current.takeError();

  auto compute_type = wrapper::BlasComputeType::FromOpaqueValue(*computeType);
  auto alpha_ptr = GetScalePointer(alpha, compute_type);
  if (!alpha_ptr) return alpha_ptr.takeError();
  auto beta_ptr = GetScalePointer(beta, compute_type);
  if (!beta_ptr) return beta_ptr.takeError();

  return wrapper::BlasGemmEx(
      *current, handle.get(), wrapper::BlasOperation::FromOpaqueValue(*transA),
      wrapper::BlasOperation::FromOpaqueValue(*transB), m, n, k, *alpha_ptr,
      A.pointer(), wrapper::BlasDataType::FromOpaqueValue(*typeA), heightA,
      B.pointer(), wrapper::BlasDataType::FromOpaqueValue(*typeB), heightB,
      *beta_ptr, C.pointer(), wrapper::BlasDataType::FromOpaqueValue(*typeC),
      heightC, compute_type, algo);
}

static Error BlasGemmBatch(
    const GpuBlasHandle& handle, int32_t m, int32_t n, int32_t k,
    AsyncValue* alpha, const GpuBuffer& A, int32_t heightA, int64_t strideA,
    const GpuBuffer& B, int32_t heightB, int64_t strideB, AsyncValue* beta,
    const GpuBuffer& C, int32_t heightC, int64_t strideC, int32_t batchCount,
    wrapper::BlasGemmAlgo algo,
    // Needs to be sorted alphabetically by attribute name!
    Attribute<int32_t> computeType, Attribute<int32_t> transA,
    Attribute<int32_t> transB, Attribute<int32_t> typeA,
    Attribute<int32_t> typeB, Attribute<int32_t> typeC) {
  auto current = wrapper::CtxSetCurrent(handle.context()->get());
  if (!current) return current.takeError();

  auto compute_type = wrapper::BlasComputeType::FromOpaqueValue(*computeType);
  auto alpha_ptr = GetScalePointer(alpha, compute_type);
  if (!alpha_ptr) return alpha_ptr.takeError();
  auto beta_ptr = GetScalePointer(beta, compute_type);
  if (!beta_ptr) return beta_ptr.takeError();

  return wrapper::BlasGemmStridedBatchedEx(
      *current, handle.get(), wrapper::BlasOperation::FromOpaqueValue(*transA),
      wrapper::BlasOperation::FromOpaqueValue(*transB), m, n, k, *alpha_ptr,
      A.pointer(), wrapper::BlasDataType::FromOpaqueValue(*typeA), heightA,
      strideA, B.pointer(), wrapper::BlasDataType::FromOpaqueValue(*typeB),
      heightB, strideB, *beta_ptr, C.pointer(),
      wrapper::BlasDataType::FromOpaqueValue(*typeC), heightC, strideC,
      batchCount, compute_type, algo);
}

static Error BlasTrsmBatch(
    const GpuBlasHandle& handle, int32_t m, int32_t n, AsyncValue* alpha,
    const GpuBuffer& A, int32_t heightA, const GpuBuffer& B, int32_t heightB,
    int32_t batchCount,
    // Needs to be sorted alphabetically by attribute name!
    Attribute<int32_t> dataType, Attribute<int32_t> diagType,
    Attribute<int32_t> fillMode, Attribute<int32_t> sideMode,
    Attribute<int32_t> trans) {
  // TODO(hanbinyoon): Also support the ROCm function corresponding to
  // cublas<t>trsmBatched.
  auto platform = handle->platform();
  if (platform != wrapper::Platform::CUDA)
    return MakeStringError("Unsupported platform ", platform);

  cudaDataType data_type = wrapper::BlasDataType::FromOpaqueValue(*dataType);
  auto alpha_ptr = GetScalePointer(alpha, data_type);
  if (!alpha_ptr) return alpha_ptr.takeError();

  auto call = [&](auto dummy) {
    auto current = wrapper::CtxSetCurrent(handle.context()->get());
    if (!current) return current.takeError();

    using T = decltype(dummy);
    auto pointer_array =
        handle.context()->AllocateHostPoolMemory<T*>(*current, 2 * batchCount);
    if (!pointer_array) return pointer_array.takeError();
    T** b_array = pointer_array->get().raw(platform);
    const T** a_array = const_cast<const T**>(b_array + batchCount);

    auto side_mode = wrapper::BlasSideMode::FromOpaqueValue(*sideMode);
    ptrdiff_t a_batch_stride = side_mode == CUBLAS_SIDE_LEFT ? m * m : n * n;
    ptrdiff_t b_batch_stride = m * n;
    const T* a_ptr = static_cast<const T*>(A.pointer().raw(platform));
    T* b_ptr = static_cast<T*>(B.pointer().raw(platform));
    for (int32_t i = 0; i < batchCount; ++i) {
      a_array[i] = a_ptr + i * a_batch_stride;
      b_array[i] = b_ptr + i * b_batch_stride;
    }

    wrapper::Pointer<const T*> a_array_ptr(a_array, platform);
    wrapper::Pointer<T*> b_array_ptr(b_array, platform);
    auto cast_alpha_ptr = static_cast<wrapper::Pointer<const T>>(*alpha_ptr);

    return wrapper::CublasTrsmBatched(
        *current, handle.get(), side_mode,
        wrapper::BlasFillMode::FromOpaqueValue(*fillMode),
        wrapper::BlasOperation::FromOpaqueValue(*trans),
        wrapper::BlasDiagType::FromOpaqueValue(*diagType), m, n, cast_alpha_ptr,
        a_array_ptr, heightA, b_array_ptr, heightB, batchCount);
  };

  switch (data_type) {
    case CUDA_R_32F:
      return call(float{});
    case CUDA_R_64F:
      return call(double{});
    case CUDA_C_32F:
      return call(cuComplex{});
    case CUDA_C_64F:
      return call(cuDoubleComplex{});
    default:
      return MakeStringError("Unsupported data type ", data_type);
  }
}

void RegisterGpuBlasKernels(KernelRegistry* kernel_reg) {
  kernel_reg->AddKernel("tfrt_gpu.blas.create", TFRT_KERNEL(BlasCreate));
  kernel_reg->AddKernel("tfrt_gpu.blas.axpy",
                        TFRT_KERNEL_WITH_CHAIN_RESULT(BlasAxpy));
  kernel_reg->AddKernel("tfrt_gpu.blas.gemm.algo", TFRT_KERNEL(BlasGemmAlgo));
  kernel_reg->AddKernel("tfrt_gpu.blas.gemm",
                        TFRT_KERNEL_WITH_CHAIN_RESULT(BlasGemm));
  kernel_reg->AddKernel("tfrt_gpu.blas.gemm.batch",
                        TFRT_KERNEL_WITH_CHAIN_RESULT(BlasGemmBatch));
  kernel_reg->AddKernel("tfrt_gpu.blas.trsm.batch",
                        TFRT_KERNEL_WITH_CHAIN_RESULT(BlasTrsmBatch));
}
}  // namespace gpu
}  // namespace tfrt
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993-2011 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

// interface header
#include "ErrorHandler.h"

// system headers
#include <stdio.h>
#include <stdarg.h>
#include <vector>
#include <string>

// local implementation headers
#include "bzfio.h"
#include "BundleMgr.h"
#include "Bundle.h"

static ErrorCallback	errorCallback = NULL;

ErrorCallback		setErrorCallback(ErrorCallback cb)
{
  ErrorCallback oldErrorCallback = errorCallback;
  errorCallback = cb;
  return oldErrorCallback;
}

void			printError(const std::string &fmt, const std::vector<std::string> *parms)
{
  std::string msg;
  Bundle *pBdl = BundleMgr::getCurrentBundle();
  if (!pBdl)
    return;

  if ((parms != NULL) && (parms->size() > 0))
    msg = pBdl->formatMessage(fmt, parms);
  else
    msg = pBdl->getLocalString(fmt);

  if (errorCallback) (*errorCallback)(msg.c_str());
#if defined(_WIN32)
  else { OutputDebugString(msg.c_str()); OutputDebugString("\n"); }
#else
  else std::cerr << msg << std::endl;
#endif
}

//
// special error handler.  shows a message box on Windows.
//

void			printFatalError(const char* fmt, ...)
{
  char buffer[1024];
  va_list args;
  va_start(args, fmt);
  vsprintf(buffer, fmt, args);
  va_end(args);
#if defined(_WIN32)
  MessageBox(NULL, buffer, "BZFlag Error", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
  std::cerr << buffer << std::endl;
#endif
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<commit_msg>(performance) Possible inefficient checking for 'parms' emptiness.<commit_after>/* bzflag
 * Copyright (c) 1993-2011 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

// interface header
#include "ErrorHandler.h"

// system headers
#include <stdio.h>
#include <stdarg.h>
#include <vector>
#include <string>

// local implementation headers
#include "bzfio.h"
#include "BundleMgr.h"
#include "Bundle.h"

static ErrorCallback	errorCallback = NULL;

ErrorCallback		setErrorCallback(ErrorCallback cb)
{
  ErrorCallback oldErrorCallback = errorCallback;
  errorCallback = cb;
  return oldErrorCallback;
}

void			printError(const std::string &fmt, const std::vector<std::string> *parms)
{
  std::string msg;
  Bundle *pBdl = BundleMgr::getCurrentBundle();
  if (!pBdl)
    return;

  if ((parms != NULL) && !parms->empty())
    msg = pBdl->formatMessage(fmt, parms);
  else
    msg = pBdl->getLocalString(fmt);

  if (errorCallback) (*errorCallback)(msg.c_str());
#if defined(_WIN32)
  else { OutputDebugString(msg.c_str()); OutputDebugString("\n"); }
#else
  else std::cerr << msg << std::endl;
#endif
}

//
// special error handler.  shows a message box on Windows.
//

void			printFatalError(const char* fmt, ...)
{
  char buffer[1024];
  va_list args;
  va_start(args, fmt);
  vsprintf(buffer, fmt, args);
  va_end(args);
#if defined(_WIN32)
  MessageBox(NULL, buffer, "BZFlag Error", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
  std::cerr << buffer << std::endl;
#endif
}

// Local Variables: ***
// mode:C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8

<|endoftext|>