<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2011 Francois Beaune
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Project headers.
#include "commandlinehandler.h"
#include "defaults.h"

// appleseed.shared headers.
#include "application/application.h"
#include "application/superlogger.h"

// appleseed.renderer headers.
#include "renderer/api/camera.h"
#include "renderer/api/project.h"
#include "renderer/api/scene.h"

// appleseed.foundation headers.
#include "foundation/math/aabb.h"
#include "foundation/math/matrix.h"
#include "foundation/math/scalar.h"
#include "foundation/math/transform.h"
#include "foundation/math/vector.h"
#include "foundation/utility/autoreleaseptr.h"
#include "foundation/utility/log.h"
#include "foundation/utility/string.h"

// boost headers.
#include "boost/filesystem/path.hpp"

// Standard headers.
#include <cmath>
#include <cstddef>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include <string>

using namespace appleseed::animatecamera;
using namespace appleseed::shared;
using namespace boost;
using namespace foundation;
using namespace renderer;
using namespace std;

namespace
{
    CommandLineHandler g_cl;

    string make_numbered_filename(
        const string    filename,
        const size_t    frame,
        const size_t    digits = 4)
    {
        const filesystem::path path(filename);

        stringstream sstr;
        sstr << path.stem();
        sstr << '.';
        sstr << setw(digits) << setfill('0') << frame;
        sstr << path.extension();

        return sstr.str();
    }

    void generate_project_files(
        const string    base_output_filename,
        const int       frame_count)
    {
        // Construct the schema filename.
        const filesystem::path schema_path =
              filesystem::path(Application::get_root_path())
            / "schemas/project.xsd";

        // Load the input project from disk.
        ProjectFileReader reader;
        auto_release_ptr<Project> project(
            reader.read(
                g_cl.m_filenames.values()[0].c_str(),
                schema_path.file_string().c_str()));

        // Bail out if the project couldn't be loaded.
        if (project.get() == 0)
            exit(1);

        // Retrieve the scene's bounding box.
        const AABB3d scene_bbox(project->get_scene()->compute_bbox());
        const Vector3d extent = scene_bbox.extent();
        const double max_radius = 0.5 * max(extent.x, extent.z);
        const double max_height = 0.5 * extent.y;

        // Retrieve the command line parameter values.
        const Vector3d center_offset(
            g_cl.m_camera_target.values()[0],
            g_cl.m_camera_target.values()[1],
            g_cl.m_camera_target.values()[2]);
        const double normalized_distance = g_cl.m_camera_distance.values()[0];
        const double normalized_elevation = g_cl.m_camera_elevation.values()[0];

        for (int i = 0; i < frame_count; ++i)
        {
            // Compute the position of the camera at this frame.
            const double angle = static_cast<double>(i) / frame_count * TwoPi;
            const double distance = max_radius * normalized_distance;
            const double elevation = max_height * normalized_elevation;
            const Vector3d position(
                distance * cos(angle),
                elevation,
                distance * sin(angle));

            // Compute and set the transform of the camera at this frame.
            const Vector3d center = scene_bbox.center() + center_offset;
            const Vector3d Up(0.0, 1.0, 0.0);
            Camera* camera = project->get_scene()->get_camera();
            camera->set_transform(Transformd(Matrix4d::lookat(position, center, Up)));

            // Write the project file for this frame.
            const string new_path = make_numbered_filename(base_output_filename + ".appleseed", i + 1);
            project->set_path(new_path.c_str());
            ProjectFileWriter::write(project.ref(), false);
        }
    }

    void generate_windows_render_script(
        const string    base_output_filename,
        const int       frame_count,
        SuperLogger&    logger)
    {
        LOG_INFO(logger, "generating batch file...");

        const char* BatchFileName = "render.bat";

        FILE* batch_file = fopen(BatchFileName, "wt");

        if (batch_file == 0)
            LOG_FATAL(logger, "could not write to %s.", BatchFileName);

        fprintf(
            batch_file,
            "%s",
            "@echo off\n"
            "\n"
            "set bin=\"%1\"\n"
            "\n"
            "if %bin% == \"\" (\n"
            "    echo Usage: %0 path-to-appleseed-binary\n"
            "    goto :end\n"
            ")\n"
            "\n"
            "if not exist %bin% (\n"
            "    echo Could not find %bin%, exiting.\n"
            "    goto :end\n"
            ")\n"
            "\n"
            "if not exist frames (\n"
            "    mkdir frames\n"
            ")\n"
            "\n");

        for (int i = 0; i < frame_count; ++i)
        {
            const string project_filename = make_numbered_filename(base_output_filename + ".appleseed", i + 1);
            const string image_filename = make_numbered_filename(base_output_filename + ".png", i + 1);

            const size_t LineLength = 80 + 1;   // +1 to account for the escape character
            const string header = "--- " + project_filename + " -^> " + image_filename + " ";
            const string header_suffix(header.size() < LineLength ? LineLength - header.size() : 0, '-');

            fprintf(
                batch_file,
                "echo %s%s\n",
                header.c_str(),
                header_suffix.c_str());

            fprintf(
                batch_file,
                "%%bin%% %s -o frames\\%s\n",
                project_filename.c_str(),
                image_filename.c_str());
        }

        fprintf(
            batch_file,
            "%s",
            "\n"
            "echo.\n"
            "\n"
            ":end\n");

        fclose(batch_file);
    }
}

//
// Entry point of animatecamera.
//

int main(int argc, const char* argv[])
{
    SuperLogger logger;

    Application::check_installation(logger);

    g_cl.parse(argc, argv, logger);

    const string base_output_filename =
        filesystem::path(g_cl.m_filenames.values()[1]).stem();

    const int frame_count = g_cl.m_frame_count.values()[0];

    if (frame_count < 1)
        LOG_FATAL(logger, "the frame count must be greater than or equal to 1.");

    global_logger().add_target(&logger.get_log_target());

    generate_project_files(base_output_filename, frame_count);

#ifdef _WIN32
    generate_windows_render_script(
        base_output_filename,
        frame_count,
        logger);
#endif

    return 0;
}
<commit_msg>the render script generated by animatecamera now skips frames that were already rendered.<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2011 Francois Beaune
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Project headers.
#include "commandlinehandler.h"
#include "defaults.h"

// appleseed.shared headers.
#include "application/application.h"
#include "application/superlogger.h"

// appleseed.renderer headers.
#include "renderer/api/camera.h"
#include "renderer/api/project.h"
#include "renderer/api/scene.h"

// appleseed.foundation headers.
#include "foundation/math/aabb.h"
#include "foundation/math/matrix.h"
#include "foundation/math/scalar.h"
#include "foundation/math/transform.h"
#include "foundation/math/vector.h"
#include "foundation/utility/autoreleaseptr.h"
#include "foundation/utility/log.h"
#include "foundation/utility/string.h"

// boost headers.
#include "boost/filesystem/path.hpp"

// Standard headers.
#include <cmath>
#include <cstddef>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#include <string>

using namespace appleseed::animatecamera;
using namespace appleseed::shared;
using namespace boost;
using namespace foundation;
using namespace renderer;
using namespace std;

namespace
{
    CommandLineHandler g_cl;

    string make_numbered_filename(
        const string    filename,
        const size_t    frame,
        const size_t    digits = 4)
    {
        const filesystem::path path(filename);

        stringstream sstr;
        sstr << path.stem();
        sstr << '.';
        sstr << setw(digits) << setfill('0') << frame;
        sstr << path.extension();

        return sstr.str();
    }

    void generate_project_files(
        const string    base_output_filename,
        const int       frame_count)
    {
        // Construct the schema filename.
        const filesystem::path schema_path =
              filesystem::path(Application::get_root_path())
            / "schemas/project.xsd";

        // Load the input project from disk.
        ProjectFileReader reader;
        auto_release_ptr<Project> project(
            reader.read(
                g_cl.m_filenames.values()[0].c_str(),
                schema_path.file_string().c_str()));

        // Bail out if the project couldn't be loaded.
        if (project.get() == 0)
            exit(1);

        // Retrieve the scene's bounding box.
        const AABB3d scene_bbox(project->get_scene()->compute_bbox());
        const Vector3d extent = scene_bbox.extent();
        const double max_radius = 0.5 * max(extent.x, extent.z);
        const double max_height = 0.5 * extent.y;

        // Retrieve the command line parameter values.
        const Vector3d center_offset(
            g_cl.m_camera_target.values()[0],
            g_cl.m_camera_target.values()[1],
            g_cl.m_camera_target.values()[2]);
        const double normalized_distance = g_cl.m_camera_distance.values()[0];
        const double normalized_elevation = g_cl.m_camera_elevation.values()[0];

        for (int i = 0; i < frame_count; ++i)
        {
            // Compute the position of the camera at this frame.
            const double angle = static_cast<double>(i) / frame_count * TwoPi;
            const double distance = max_radius * normalized_distance;
            const double elevation = max_height * normalized_elevation;
            const Vector3d position(
                distance * cos(angle),
                elevation,
                distance * sin(angle));

            // Compute and set the transform of the camera at this frame.
            const Vector3d center = scene_bbox.center() + center_offset;
            const Vector3d Up(0.0, 1.0, 0.0);
            Camera* camera = project->get_scene()->get_camera();
            camera->set_transform(Transformd(Matrix4d::lookat(position, center, Up)));

            // Write the project file for this frame.
            const int frame = i + 1;
            const string new_path = make_numbered_filename(base_output_filename + ".appleseed", frame);
            project->set_path(new_path.c_str());
            ProjectFileWriter::write(project.ref(), false);
        }
    }

    void generate_windows_render_script(
        const string    base_output_filename,
        const int       frame_count,
        SuperLogger&    logger)
    {
        LOG_INFO(logger, "generating batch file...");

        const char* BatchFileName = "render.bat";

        FILE* batch_file = fopen(BatchFileName, "wt");

        if (batch_file == 0)
            LOG_FATAL(logger, "could not write to %s.", BatchFileName);

        fprintf(
            batch_file,
            "%s",
            "@echo off\n"
            "\n"
            "set bin=\"%1\"\n"
            "\n"
            "if %bin% == \"\" (\n"
            "    echo Usage: %0 path-to-appleseed-binary\n"
            "    goto :end\n"
            ")\n"
            "\n"
            "if not exist %bin% (\n"
            "    echo Could not find %bin%, exiting.\n"
            "    goto :end\n"
            ")\n"
            "\n"
            "if not exist frames (\n"
            "    mkdir frames\n"
            ")\n"
            "\n");

        for (int i = 0; i < frame_count; ++i)
        {
            const int frame = i + 1;
            const string project_filename = make_numbered_filename(base_output_filename + ".appleseed", frame);
            const string image_filename = make_numbered_filename(base_output_filename + ".png", frame);

            const size_t LineLength = 80 + 1;   // +1 to account for the escape character
            const string header = "--- " + project_filename + " -^> " + image_filename + " ";
            const string header_suffix(header.size() < LineLength ? LineLength - header.size() : 0, '-');

            fprintf(batch_file, "if exist \"frames\\%s\" (\n", image_filename.c_str());
            fprintf(batch_file, "    echo Skipping %s...\n", project_filename.c_str());
            fprintf(batch_file, ") else (\n");
            fprintf(batch_file, "    echo %s%s\n", header.c_str(), header_suffix.c_str());
            fprintf(batch_file, "    %%bin%% %s -o \"frames\\%s\"\n", project_filename.c_str(), image_filename.c_str());
            fprintf(batch_file, ")\n");
        }

        fprintf(
            batch_file,
            "%s",
            "\n"
            "echo.\n"
            "\n"
            ":end\n");

        fclose(batch_file);
    }
}

//
// Entry point of animatecamera.
//

int main(int argc, const char* argv[])
{
    SuperLogger logger;

    Application::check_installation(logger);

    g_cl.parse(argc, argv, logger);

    const string base_output_filename =
        filesystem::path(g_cl.m_filenames.values()[1]).stem();

    const int frame_count = g_cl.m_frame_count.values()[0];

    if (frame_count < 1)
        LOG_FATAL(logger, "the frame count must be greater than or equal to 1.");

    global_logger().add_target(&logger.get_log_target());

    generate_project_files(base_output_filename, frame_count);

#ifdef _WIN32
    generate_windows_render_script(
        base_output_filename,
        frame_count,
        logger);
#endif

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#ifndef RUNNER_STATE_HXX
# define RUNNER_STATE_HXX

# include <libport/bind.hh>
# include <libport/config.h>
# include <libport/compilation.hh>

# include <ast/local-assignment.hh>
# include <ast/local-declaration.hh>
# include <ast/local.hh>
# include <object/symbols.hh>
# include <runner/stacks.hh>
# include <urbi/object/slot.hh>
# include <urbi/object/slot.hxx>

namespace runner
{

  /// Handle tags.
  /// \{

  LIBPORT_SPEED_INLINE void
  State::update_priority_cache(sched::prio_type prio)
  {
    // FIXME: Previously, this code was refering to
    // scheduler_get().real_time_behavior_get() to avoid the computation of
    // the priority, but with a cache, there is no need to check for it
    // because the execution time is bounded and small.  But this is still
    // not real-time.  To make it real-time, the job priority should be
    // stored with the corresponding tag.  Thus the priority would be
    // computed incrementally.
    if (prio >= priority_cache_)
      priority_cache_valid_ = false;
    if (tag_stack_.empty())
      priority_cache_ = priority();
  }

  LIBPORT_SPEED_INLINE void
  State::apply_tag(const object::rTag& tag, libport::Finally* finally)
  {
    tag_stack_push(tag);
    if (finally)
      *finally << boost::bind(&State::tag_stack_pop, this);
  }

  LIBPORT_SPEED_ALWAYS_INLINE void
  State::tag_stack_clear()
  {
    tag_stack_.clear();
  }

  LIBPORT_SPEED_ALWAYS_INLINE const State::tag_stack_type&
  State::tag_stack_get_all() const
  {
    return tag_stack_;
  }

  LIBPORT_SPEED_ALWAYS_INLINE void
  State::tag_stack_set(const tag_stack_type& tag_stack)
  {
    tag_stack_ = tag_stack;
  }

  LIBPORT_SPEED_ALWAYS_INLINE size_t
  State::tag_stack_size() const
  {
    return tag_stack_.size();
  }

  LIBPORT_SPEED_INLINE void
  State::tag_stack_push(const object::rTag& tag)
  {
    tag_stack_.push_back(tag);
    update_priority_cache(tag->value_get()->prio_get());
  }

  LIBPORT_SPEED_INLINE void
  State::tag_stack_pop()
  {
    const object::rTag& tag = tag_stack_.back();
    sched::prio_type prio = tag->value_get()->prio_get();
    tag_stack_.pop_back();
    update_priority_cache(prio);
  }

  LIBPORT_SPEED_INLINE void
  State::frozen_set(bool v)
  {
    frozen_ = v;
  }

  /// \}

  /// Scope tag
  /// \{

  // Scope tag are likely to be removed by static analysis.

  LIBPORT_SPEED_INLINE
  const sched::rTag&
  State::scope_tag(sched::Scheduler& sched)
  {
    sched::rTag& tag = scope_tags_.back();
    if (!tag)
    {
      // Create the tag on demand. It must have the lowest possible priority
      // to avoid influencing the scheduling algorithm.
      tag = new sched::Tag(); // ScopeTag
      tag->prio_set(sched, sched::UPRIO_NONE);
    }
    return tag;
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void
  State::create_scope_tag()
  {
    // Push a scopeTag into existence, but do not allocate it until it is
    // used with the scope_tag function.
    scope_tags_.push_back(0);
  }

  LIBPORT_SPEED_INLINE
  void
  State::cleanup_scope_tag(sched::Scheduler& sched)
  {
    const sched::rTag& tag = scope_tags_.back();
    if (tag)
      tag->stop(sched, object::void_class);
    scope_tags_.pop_back();
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  const sched::rTag&
  State::scope_tag_get() const
  {
    return scope_tags_.back();
  }

  /// \}

  /// Call Stack
  /// \{

  LIBPORT_SPEED_ALWAYS_INLINE
  const State::call_stack_type&
  State::call_stack_get() const
  {
    return call_stack_;
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  State::call_stack_type&
  State::call_stack_get()
  {
    return call_stack_;
  }

  LIBPORT_SPEED_INLINE
  libport::Symbol
  State::innermost_call_get() const
  {
    if (call_stack_.empty())
      return SYMBOL(LT_empty_GT);
    else
      return call_stack_.back().first;
  }

  /// \}

  /// Frame stack
  /// \{

  // This is a duplication of the interface of Stacks, but this is
  // temporary and should be modified as soon as the State can be
  // separated in multiple independent and/or inter-dependent components
  // to handle the state of a job.

  // This wrapper may cause a source of performance lost due to ref-counted
  // arguments on which the inlining keep the original semantic of
  // incrementing multiple times the counter.

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::execution_starts(libport::Symbol msg)
  {
    stacks_.execution_starts(msg);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  State::var_frame_type
  State::push_frame(libport::Symbol msg,
                        var_frame_type local_frame,
                        rObject self, rObject call)
  {
    return stacks_.push_frame(msg, local_frame, self, call);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::pop_frame(libport::Symbol msg,
                            var_frame_type previous_frame)
  {
    stacks_.pop_frame(msg, previous_frame);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  State::var_context_type
  State::push_context(rObject self)
  {
    return stacks_.push_context(self);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::pop_context(const var_context_type& previous_context)
  {
    stacks_.pop_context(previous_context);
  }

  /*-----------------.
  | Reading values.  |
  `-----------------*/

  LIBPORT_SPEED_ALWAYS_INLINE
  State::rObject
  State::get(ast::rConstLocal e)
  {
    return stacks_.get(e);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  State::rSlot
  State::rget(ast::rConstLocal e)
  {
    return stacks_.rget(e);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  State::rSlot
  State::rget_assignment(ast::rConstLocalAssignment e)
  {
    return stacks_.rget_assignment(e);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  State::rObject
  State::this_get()
  {
    return stacks_.this_get();
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  State::rObject
  State::call()
  {
    return stacks_.call();
  }

  /*-----------------.
  | Setting values.  |
  `-----------------*/

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::this_set(rObject s)
  {
    stacks_.this_set(s);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::call_set(rObject v)
  {
    stacks_.call_set(v);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::set(ast::rConstLocalAssignment e, rObject v)
  {
    stacks_.set(e, v);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::def(ast::rConstLocalDeclaration e, rObject v,
                      bool constant)
  {
    stacks_.def(e, v, constant);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::def_arg(ast::rConstLocalDeclaration e, rObject v)
  {
    stacks_.def_arg(e, v);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::def_captured(ast::rConstLocalDeclaration e, rSlot v)
  {
    stacks_.def_captured(e, v);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::this_switch(rObject s)
  {
    stacks_.this_switch(s);
  }

  /// \}

  /// Lobby
  /// \{

  LIBPORT_SPEED_ALWAYS_INLINE
  State::Lobby* State::lobby_get()
  {
    return lobby_.get();
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::lobby_set(Lobby* lobby)
  {
    lobby_ = lobby;
  }

  /// \}

  /// \ name Last location
  /// \{

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::innermost_node_set(const ast::Ast* n)
  {
    innermost_node_ = n;
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  const ast::Ast* State::innermost_node_get() const
  {
    return innermost_node_;
  }

  /// \}

} // namespace runner

#endif // ! RUNNER_STATE_HXX
<commit_msg>Runner: Notify scheduler when a job gets unfrozen.<commit_after>/*
 * Copyright (C) 2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#ifndef RUNNER_STATE_HXX
# define RUNNER_STATE_HXX

# include <libport/bind.hh>
# include <libport/config.h>
# include <libport/compilation.hh>

# include <ast/local-assignment.hh>
# include <ast/local-declaration.hh>
# include <ast/local.hh>
# include <object/symbols.hh>
# include <runner/stacks.hh>
# include <urbi/object/slot.hh>
# include <urbi/object/slot.hxx>

# include <kernel/userver.hh>

namespace runner
{

  /// Handle tags.
  /// \{

  LIBPORT_SPEED_INLINE void
  State::update_priority_cache(sched::prio_type prio)
  {
    // FIXME: Previously, this code was refering to
    // scheduler_get().real_time_behavior_get() to avoid the computation of
    // the priority, but with a cache, there is no need to check for it
    // because the execution time is bounded and small.  But this is still
    // not real-time.  To make it real-time, the job priority should be
    // stored with the corresponding tag.  Thus the priority would be
    // computed incrementally.
    if (prio >= priority_cache_)
      priority_cache_valid_ = false;
    if (tag_stack_.empty())
      priority_cache_ = priority();
  }

  LIBPORT_SPEED_INLINE void
  State::apply_tag(const object::rTag& tag, libport::Finally* finally)
  {
    tag_stack_push(tag);
    if (finally)
      *finally << boost::bind(&State::tag_stack_pop, this);
  }

  LIBPORT_SPEED_ALWAYS_INLINE void
  State::tag_stack_clear()
  {
    tag_stack_.clear();
  }

  LIBPORT_SPEED_ALWAYS_INLINE const State::tag_stack_type&
  State::tag_stack_get_all() const
  {
    return tag_stack_;
  }

  LIBPORT_SPEED_ALWAYS_INLINE void
  State::tag_stack_set(const tag_stack_type& tag_stack)
  {
    tag_stack_ = tag_stack;
  }

  LIBPORT_SPEED_ALWAYS_INLINE size_t
  State::tag_stack_size() const
  {
    return tag_stack_.size();
  }

  LIBPORT_SPEED_INLINE void
  State::tag_stack_push(const object::rTag& tag)
  {
    tag_stack_.push_back(tag);
    update_priority_cache(tag->value_get()->prio_get());
  }

  LIBPORT_SPEED_INLINE void
  State::tag_stack_pop()
  {
    const object::rTag& tag = tag_stack_.back();
    sched::prio_type prio = tag->value_get()->prio_get();
    tag_stack_.pop_back();
    update_priority_cache(prio);
  }

  LIBPORT_SPEED_INLINE void
  State::frozen_set(bool v)
  {
    if (frozen_ && !v)
      kernel::server().scheduler_get().job_was_woken_up();
    frozen_ = v;
  }

  /// \}

  /// Scope tag
  /// \{

  // Scope tag are likely to be removed by static analysis.

  LIBPORT_SPEED_INLINE
  const sched::rTag&
  State::scope_tag(sched::Scheduler& sched)
  {
    sched::rTag& tag = scope_tags_.back();
    if (!tag)
    {
      // Create the tag on demand. It must have the lowest possible priority
      // to avoid influencing the scheduling algorithm.
      tag = new sched::Tag(); // ScopeTag
      tag->prio_set(sched, sched::UPRIO_NONE);
    }
    return tag;
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void
  State::create_scope_tag()
  {
    // Push a scopeTag into existence, but do not allocate it until it is
    // used with the scope_tag function.
    scope_tags_.push_back(0);
  }

  LIBPORT_SPEED_INLINE
  void
  State::cleanup_scope_tag(sched::Scheduler& sched)
  {
    const sched::rTag& tag = scope_tags_.back();
    if (tag)
      tag->stop(sched, object::void_class);
    scope_tags_.pop_back();
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  const sched::rTag&
  State::scope_tag_get() const
  {
    return scope_tags_.back();
  }

  /// \}

  /// Call Stack
  /// \{

  LIBPORT_SPEED_ALWAYS_INLINE
  const State::call_stack_type&
  State::call_stack_get() const
  {
    return call_stack_;
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  State::call_stack_type&
  State::call_stack_get()
  {
    return call_stack_;
  }

  LIBPORT_SPEED_INLINE
  libport::Symbol
  State::innermost_call_get() const
  {
    if (call_stack_.empty())
      return SYMBOL(LT_empty_GT);
    else
      return call_stack_.back().first;
  }

  /// \}

  /// Frame stack
  /// \{

  // This is a duplication of the interface of Stacks, but this is
  // temporary and should be modified as soon as the State can be
  // separated in multiple independent and/or inter-dependent components
  // to handle the state of a job.

  // This wrapper may cause a source of performance lost due to ref-counted
  // arguments on which the inlining keep the original semantic of
  // incrementing multiple times the counter.

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::execution_starts(libport::Symbol msg)
  {
    stacks_.execution_starts(msg);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  State::var_frame_type
  State::push_frame(libport::Symbol msg,
                        var_frame_type local_frame,
                        rObject self, rObject call)
  {
    return stacks_.push_frame(msg, local_frame, self, call);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::pop_frame(libport::Symbol msg,
                            var_frame_type previous_frame)
  {
    stacks_.pop_frame(msg, previous_frame);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  State::var_context_type
  State::push_context(rObject self)
  {
    return stacks_.push_context(self);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::pop_context(const var_context_type& previous_context)
  {
    stacks_.pop_context(previous_context);
  }

  /*-----------------.
  | Reading values.  |
  `-----------------*/

  LIBPORT_SPEED_ALWAYS_INLINE
  State::rObject
  State::get(ast::rConstLocal e)
  {
    return stacks_.get(e);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  State::rSlot
  State::rget(ast::rConstLocal e)
  {
    return stacks_.rget(e);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  State::rSlot
  State::rget_assignment(ast::rConstLocalAssignment e)
  {
    return stacks_.rget_assignment(e);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  State::rObject
  State::this_get()
  {
    return stacks_.this_get();
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  State::rObject
  State::call()
  {
    return stacks_.call();
  }

  /*-----------------.
  | Setting values.  |
  `-----------------*/

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::this_set(rObject s)
  {
    stacks_.this_set(s);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::call_set(rObject v)
  {
    stacks_.call_set(v);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::set(ast::rConstLocalAssignment e, rObject v)
  {
    stacks_.set(e, v);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::def(ast::rConstLocalDeclaration e, rObject v,
                      bool constant)
  {
    stacks_.def(e, v, constant);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::def_arg(ast::rConstLocalDeclaration e, rObject v)
  {
    stacks_.def_arg(e, v);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::def_captured(ast::rConstLocalDeclaration e, rSlot v)
  {
    stacks_.def_captured(e, v);
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::this_switch(rObject s)
  {
    stacks_.this_switch(s);
  }

  /// \}

  /// Lobby
  /// \{

  LIBPORT_SPEED_ALWAYS_INLINE
  State::Lobby* State::lobby_get()
  {
    return lobby_.get();
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::lobby_set(Lobby* lobby)
  {
    lobby_ = lobby;
  }

  /// \}

  /// \ name Last location
  /// \{

  LIBPORT_SPEED_ALWAYS_INLINE
  void State::innermost_node_set(const ast::Ast* n)
  {
    innermost_node_ = n;
  }

  LIBPORT_SPEED_ALWAYS_INLINE
  const ast::Ast* State::innermost_node_get() const
  {
    return innermost_node_;
  }

  /// \}

} // namespace runner

#endif // ! RUNNER_STATE_HXX
<|endoftext|>


<commit_before>//
// Simple example to demonstrate how to use DroneCore.
//
// Author: Julian Oes <julian@oes.ch>

#include <dronecore/dronecore.h>
#include <iostream>
#include <thread>
#include <chrono>
#include <cstdint>

using namespace dronecore;

int main(int /*argc*/, char ** /*argv*/)
{
    DroneCore dc;

    bool discovered_device = false;

    DroneCore::ConnectionResult connection_result = dc.add_udp_connection();

    if (connection_result != DroneCore::ConnectionResult::SUCCESS) {
        std::cout << "\033[31m" << "Connection failed: " << DroneCore::connection_result_str(
                      connection_result) << "\033[0m" << std::endl;
        return 1;
    }

    std::cout << "Waiting to discover device..." << std::endl;
    dc.register_on_discover([&discovered_device](uint64_t uuid) {
        std::cout << "Discovered device with UUID: " << uuid << std::endl;
        discovered_device = true;
    });

    // We usually receive heartbeats at 1Hz, therefore we should find a device after around 2 seconds.
    std::this_thread::sleep_for(std::chrono::seconds(2));

    if (!discovered_device) {
        std::cout << "\033[31m" << "No device found, exiting." << "\033[0m" << std::endl;
        return 1;
    }

    // We don't need to specify the UUID if it's only one device anyway.
    // If there were multiple, we could specify it with:
    // dc.device(uint64_t uuid);
    Device &device = dc.device();

    // We want to listen to the altitude of the drone at 1 Hz.
    const Telemetry::Result set_rate_result = dc.device().telemetry().set_rate_position(1.0);
    if (set_rate_result != Telemetry::Result::SUCCESS) {
        std::cout << "\033[31m" << "Setting rate failed:" << Telemetry::result_str(set_rate_result) << "\033[0m" << std::endl;
        return 1;
    }

    device.telemetry().position_async([](Telemetry::Position position) {
        std::cout << "\033[34m" // set to blue
                  << "Altitude: " << position.relative_altitude_m << " m"
                  << "\033[0m" // set to default color again
                  << std::endl;
    });

    std::cout << "Arming..." << std::endl;
    const Action::Result arm_result = device.action().arm();

    if (arm_result != Action::Result::SUCCESS) {
        std::cout << "\033[31m" << "Arming failed:" << Action::result_str(arm_result) << "\033[0m" << std::endl;
        return 1;
    }

    std::cout << "Taking off..." << std::endl;
    const Action::Result takeoff_result = device.action().takeoff();
    if (takeoff_result != Action::Result::SUCCESS) {
        std::cout << "\033[31m" << "Takeoff failed:" << Action::result_str(takeoff_result) << "\033[0m" << std::endl;
        return 1;
    }

    // Let it hover for a bit before landing again.
    std::this_thread::sleep_for(std::chrono::seconds(10));

    std::cout << "Landing..." << std::endl;
    const Action::Result land_result = device.action().land();
    if (land_result != Action::Result::SUCCESS) {
        std::cout << "\033[31m" << "Land failed:" << Action::result_str(land_result) << "\033[0m" << std::endl;
        return 1;
    }

    // We are relying on auto-disarming but let's keep watching the telemetry for a bit longer.
    std::this_thread::sleep_for(std::chrono::seconds(5));

    return 0;
}
<commit_msg>Add check for being ready to arm<commit_after>//
// Simple example to demonstrate how to use DroneCore.
//
// Author: Julian Oes <julian@oes.ch>

#include <dronecore/dronecore.h>
#include <iostream>
#include <thread>
#include <chrono>
#include <cstdint>

using namespace dronecore;

int main(int /*argc*/, char ** /*argv*/)
{
    DroneCore dc;

    bool discovered_device = false;

    DroneCore::ConnectionResult connection_result = dc.add_udp_connection();

    if (connection_result != DroneCore::ConnectionResult::SUCCESS) {
        std::cout << "\033[31m" << "Connection failed: " << DroneCore::connection_result_str(
                      connection_result) << "\033[0m" << std::endl;
        return 1;
    }

    std::cout << "Waiting to discover device..." << std::endl;
    dc.register_on_discover([&discovered_device](uint64_t uuid) {
        std::cout << "Discovered device with UUID: " << uuid << std::endl;
        discovered_device = true;
    });

    // We usually receive heartbeats at 1Hz, therefore we should find a device after around 2 seconds.
    std::this_thread::sleep_for(std::chrono::seconds(2));

    if (!discovered_device) {
        std::cout << "\033[31m" << "No device found, exiting." << "\033[0m" << std::endl;
        return 1;
    }

    // We don't need to specify the UUID if it's only one device anyway.
    // If there were multiple, we could specify it with:
    // dc.device(uint64_t uuid);
    Device &device = dc.device();

    // We want to listen to the altitude of the drone at 1 Hz.
    const Telemetry::Result set_rate_result = dc.device().telemetry().set_rate_position(1.0);
    if (set_rate_result != Telemetry::Result::SUCCESS) {
        std::cout << "\033[31m" << "Setting rate failed:" << Telemetry::result_str(set_rate_result) << "\033[0m" << std::endl;
        return 1;
    }

    // Set up callback to monitor altitude while the vehicle is in flight
    device.telemetry().position_async([](Telemetry::Position position) {
        std::cout << "\033[34m" // set to blue
                  << "Altitude: " << position.relative_altitude_m << " m"
                  << "\033[0m" // set to default color again
                  << std::endl;
    });

    // Check if vehicle is ready to arm
    if (device.telemetry().health_all_ok()!=true) {
        std::cout << "\033[31m" << "Vehicle not ready to arm" << "\033[0m" << std::endl;
        return 1;
        }

    // Arm vehicle
    std::cout << "Arming..." << std::endl;
    const Action::Result arm_result = device.action().arm();

    if (arm_result != Action::Result::SUCCESS) {
        std::cout << "\033[31m" << "Arming failed:" << Action::result_str(arm_result) << "\033[0m" << std::endl;
        return 1;
    }

    // Take off
    std::cout << "Taking off..." << std::endl;
    const Action::Result takeoff_result = device.action().takeoff();
    if (takeoff_result != Action::Result::SUCCESS) {
        std::cout << "\033[31m" << "Takeoff failed:" << Action::result_str(takeoff_result) << "\033[0m" << std::endl;
        return 1;
    }

    // Let it hover for a bit before landing again.
    std::this_thread::sleep_for(std::chrono::seconds(10));

    std::cout << "Landing..." << std::endl;
    const Action::Result land_result = device.action().land();
    if (land_result != Action::Result::SUCCESS) {
        std::cout << "\033[31m" << "Land failed:" << Action::result_str(land_result) << "\033[0m" << std::endl;
        return 1;
    }

    // We are relying on auto-disarming but let's keep watching the telemetry for a bit longer.
    std::this_thread::sleep_for(std::chrono::seconds(5));

    return 0;
}
<|endoftext|>


<commit_before>//
// @file main.cc
// @brief Performance monitor test.
// @author Mamoru Kaminaga
// @date 2019-10-12 15:43:10
// Copyright 2019 Mamoru Kaminaga
#include <assert.h>
#include <stdio.h>
#include <wchar.h>
#include <windows.h>
#include <windowsx.h>
#include <memory>
#include <string>
#include <vector>
#include "../win32_edit_mini/edit.h"
#include "./list_view.h"
#include "./resource.h"
#include "./util.h"

#include <commctrl.h>  // Included at last.

namespace {
// List view.
std::unique_ptr<mk::ListView> list_view;
std::unique_ptr<mk::Edit> in_edit;
std::unique_ptr<mk::Edit> out_edit;
std::unique_ptr<mk::Edit> row_edit;
std::unique_ptr<mk::Edit> col_edit;
std::unique_ptr<mk::Edit> width_edit;
std::unique_ptr<mk::Edit> select_edit;

int row_max = 3;
int col_max = 3;
int select_column = 0;
std::vector<int> data_d;
std::vector<double> data_f;
std::vector<std::wstring> data_s;
std::vector<COLORREF> color_FG;
std::vector<COLORREF> color_BG;
}  // namespace

void ResetListViewForReportMode() {
  row_max = 3;
  col_max = 3;
  list_view->Resize(mk::ListView::MODE::REPORT, row_max, col_max);
  out_edit->Set(L"Reset ListView in REPORT mode.\n");
  row_edit->Set(L"%d", row_max);
  col_edit->Set(L"%d", col_max);

  // Set default data.
  data_d = {
      0,
      1,
      2,
  };
  data_f = {
      3.0,
      4.0,
      5.0,
  };
  data_s = {
      L"Apple",
      L"Banana",
      L"Grape",
  };
  list_view->SetText(0, data_s);
  list_view->SetData(1, L"%d", data_d);
  list_view->SetData(2, L"%5.3f", data_f);

  // Set column.
  list_view->SetColumnText(0, L"col 0");
  list_view->SetColumnText(1, L"col 1");
  list_view->SetColumnText(2, L"col 2");
  list_view->SetColumnWidth(0, 100);
  list_view->SetColumnWidth(1, 80);
  list_view->SetColumnWidth(2, 40);
  select_column = 0;
  width_edit->Set(L"100");
  select_edit->Set(L"0");

  // Prepare user color.
  color_FG.resize(row_max);
  color_BG.resize(row_max);
  for (auto& c : color_FG) {
    c = RGB(0x56, 0x3E, 0xA3);
  }
  for (auto& c : color_BG) {
    c = RGB(0xFF, 0xDA, 0x90);
  }
}

BOOL Cls_OnInitDialog(HWND hwnd, HWND hwnd_forcus, LPARAM lp) {
  (void)hwnd_forcus;
  (void)lp;
  (void)hwnd;

  // The icon is loaded.
  HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE);
  SendMessage(hwnd, WM_SETICON, ICON_BIG,
              (LPARAM)LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1)));

  // Edit control for test interface.
  out_edit.reset(new mk::Edit(GetDlgItem(hwnd, IDC_EDIT_OUTPUT)));
  in_edit.reset(new mk::Edit(GetDlgItem(hwnd, IDC_EDIT_INPUT)));
  row_edit.reset(new mk::Edit(GetDlgItem(hwnd, IDC_EDIT_SETROW)));
  col_edit.reset(new mk::Edit(GetDlgItem(hwnd, IDC_EDIT_SETCOL)));
  width_edit.reset(new mk::Edit(GetDlgItem(hwnd, IDC_EDIT_SETWIDTH)));
  select_edit.reset(new mk::Edit(GetDlgItem(hwnd, IDC_EDIT_SETSELECT)));

  // List view for test.
  mk::ListView::EnableListView();
  list_view.reset(new mk::ListView(GetDlgItem(hwnd, IDC_LIST1),
                                   mk::ListView::MODE::REPORT, row_max,
                                   col_max));
  ResetListViewForReportMode();

  return TRUE;
}

void Cls_OnDestroy(HWND hwnd) {
  (void)hwnd;
  PostQuitMessage(0);
  return;
}

void Cls_OnClose(HWND hwnd) {
  (void)hwnd;
  EndDialog(hwnd, TRUE);
  return;
}

void Cls_OnCommand(HWND hwnd, int id, HWND hWndCtl, UINT codeNotify) {
  (void)hwnd;
  (void)hWndCtl;
  (void)codeNotify;
  switch (id) {
    case IDLIST:
      ResetListViewForReportMode();
      break;
    case IDREPORT:
      // Reserved.
      out_edit->Add(L"Reserved\n");
      break;
    case IDICON:
      // Reserved.
      out_edit->Add(L"Reserved\n");
      break;
    case IDSMALLICON:
      // Reserved.
      out_edit->Add(L"Reserved\n");
      break;
    case IDCLEAR:
      out_edit->Add(L"Reserved\n");
      break;
    case IDCLEARALL:
      out_edit->Add(L"Reserved\n");
      break;
    case IDDELETE:
      out_edit->Add(L"Reserved\n");
      break;
    case IDDELETEALL:
      out_edit->Add(L"Reserved\n");
      break;
    case IDGETITEM:
      out_edit->Add(L"Reserved\n");
      break;
    case IDSETITEM:
      out_edit->Add(L"Reserved\n");
      break;
    case IDSETSIZE: {
      row_max = std::stoi(row_edit->Get());
      col_max = std::stoi(col_edit->Get());
      data_d.resize(row_max);
      data_f.resize(row_max);
      data_s.resize(row_max);
      color_FG.resize(row_max);
      color_BG.resize(row_max);
      // Debug string output.
      out_edit->Add(L"IDSETSIZE\n");
      out_edit->Add(L"row_max = %d, col_max = %d\n", row_max, col_max);
      out_edit->Add(L"\n");
      // Resize list view.
      list_view->Resize(mk::ListView::MODE::REPORT, row_max, col_max);
    } break;
    case IDSETWIDTH: {
      int width = std::stoi(width_edit->Get());
      list_view->SetColumnWidth(0, width);
      // Debug string output.
      out_edit->Add(L"IDSETWIDTH\n");
      out_edit->Add(L"width = %d\n", width);
      out_edit->Add(L"\n");
      break;
    }
    case IDSETSELECT: {
      int item = std::stoi(select_edit->Get());
      if ((item < 0) || (item > row_max)) {
        out_edit->Add(L"Invalid range\n");
      }
      list_view->SelectItem(item);
      // Debug string output.
      out_edit->Add(L"IDSETSELECT\n");
      out_edit->Add(L"item = %d\n", item);
      out_edit->Add(L"\n");
    } break;
    default:
      // none.
      break;
  }
  return;
}

LRESULT OnNofity(HWND hwndDlg, NMHDR* nmhdr) {
  assert(nmhdr);
  // if (nmhdr->hwndFrom == list_view->GetHandle()) {  // Access violation.
  if (nmhdr->hwndFrom == GetDlgItem(hwndDlg, IDC_LIST1)) {
    switch (nmhdr->code) {
      case LVN_COLUMNCLICK: {
        LPNMLISTVIEW lv = (LPNMLISTVIEW)nmhdr;
        // Debug string output.
        out_edit->Add(L"LVN_COLUMNCLICK\n");
        out_edit->Add(L"column = %d\n", lv->iSubItem);
        out_edit->Add(L"\n");
      } break;
      case NM_CLICK: {
        LPNMLISTVIEW lv = (LPNMLISTVIEW)nmhdr;
        // Debug string output.
        select_edit->Set(L"%d", lv->iItem);
        out_edit->Add(L"NM_CLICK\n");
        out_edit->Add(L"item = %d\n", lv->iItem);
        out_edit->Add(L"\n");
      } break;
      case NM_DBLCLK: {
        LPNMLISTVIEW lv = (LPNMLISTVIEW)nmhdr;
        // Debug string output.
        select_edit->Set(L"%d", lv->iItem);
        out_edit->Add(L"NM_DBLCLK\n");
        out_edit->Add(L"item = %d\n", lv->iItem);
        out_edit->Add(L"\n");
      } break;
      case NM_CUSTOMDRAW: {
        LPNMLVCUSTOMDRAW draw = (LPNMLVCUSTOMDRAW)nmhdr;
        switch (draw->nmcd.dwDrawStage) {
          case CDDS_PREPAINT:
            // Debug string output.
            out_edit->Add(L"CDDS_PREPAINT\n");
            // Use custom draw notification.
            SetWindowLong(hwndDlg, DWL_MSGRESULT, (LONG)CDRF_NOTIFYITEMDRAW);
            break;
          case CDDS_ITEMPREPAINT:
            assert(color_FG.size() >= draw->nmcd.dwItemSpec);
            assert(color_BG.size() >= draw->nmcd.dwItemSpec);
            draw->clrText = color_FG[draw->nmcd.dwItemSpec];
            draw->clrTextBk = color_BG[draw->nmcd.dwItemSpec];
            // Debug string output.
            out_edit->Add(L"CDDS_ITEMPREPAINT\n");
            // Use custom draw notification.
            SetWindowLong(hwndDlg, DWL_MSGRESULT, (LONG)CDRF_NEWFONT);
            break;
          default:
            // none.
            break;
        }
      }
      default:
        // none.
        break;
    }
  }
  return TRUE;
}

INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
                            LPARAM lParam) {
  switch (uMsg) {
    HANDLE_DLG_MSG(hwndDlg, WM_INITDIALOG, Cls_OnInitDialog);
    HANDLE_DLG_MSG(hwndDlg, WM_DESTROY, Cls_OnDestroy);
    HANDLE_DLG_MSG(hwndDlg, WM_CLOSE, Cls_OnClose);
    HANDLE_DLG_MSG(hwndDlg, WM_COMMAND, Cls_OnCommand);
    case WM_NOTIFY:
      return OnNofity(hwndDlg, (NMHDR*)lParam);
    default:
      return FALSE;
  }
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    LPTSTR lpsCmdLine, int nCmdShow) {
  (void)hPrevInstance;
  (void)lpsCmdLine;
  (void)nCmdShow;

  DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), nullptr, &DialogProc,
                 NULL);
  return 0;
}
<commit_msg>break label added in error guard<commit_after>//
// @file main.cc
// @brief Performance monitor test.
// @author Mamoru Kaminaga
// @date 2019-10-12 15:43:10
// Copyright 2019 Mamoru Kaminaga
#include <assert.h>
#include <stdio.h>
#include <wchar.h>
#include <windows.h>
#include <windowsx.h>
#include <memory>
#include <string>
#include <vector>
#include "../win32_edit_mini/edit.h"
#include "./list_view.h"
#include "./resource.h"
#include "./util.h"

#include <commctrl.h>  // Included at last.

namespace {
// List view.
std::unique_ptr<mk::ListView> list_view;
std::unique_ptr<mk::Edit> in_edit;
std::unique_ptr<mk::Edit> out_edit;
std::unique_ptr<mk::Edit> row_edit;
std::unique_ptr<mk::Edit> col_edit;
std::unique_ptr<mk::Edit> width_edit;
std::unique_ptr<mk::Edit> select_edit;

int row_max = 3;
int col_max = 3;
int select_column = 0;
std::vector<int> data_d;
std::vector<double> data_f;
std::vector<std::wstring> data_s;
std::vector<COLORREF> color_FG;
std::vector<COLORREF> color_BG;
}  // namespace

void ResetListViewForReportMode() {
  row_max = 3;
  col_max = 3;
  list_view->Resize(mk::ListView::MODE::REPORT, row_max, col_max);
  out_edit->Set(L"Reset ListView in REPORT mode.\n");
  row_edit->Set(L"%d", row_max);
  col_edit->Set(L"%d", col_max);

  // Set default data.
  data_d = {
      0,
      1,
      2,
  };
  data_f = {
      3.0,
      4.0,
      5.0,
  };
  data_s = {
      L"Apple",
      L"Banana",
      L"Grape",
  };
  list_view->SetText(0, data_s);
  list_view->SetData(1, L"%d", data_d);
  list_view->SetData(2, L"%5.3f", data_f);

  // Set column.
  list_view->SetColumnText(0, L"col 0");
  list_view->SetColumnText(1, L"col 1");
  list_view->SetColumnText(2, L"col 2");
  list_view->SetColumnWidth(0, 100);
  list_view->SetColumnWidth(1, 80);
  list_view->SetColumnWidth(2, 40);
  select_column = 0;
  width_edit->Set(L"100");
  select_edit->Set(L"0");

  // Prepare user color.
  color_FG.resize(row_max);
  color_BG.resize(row_max);
  for (auto& c : color_FG) {
    c = RGB(0x56, 0x3E, 0xA3);
  }
  for (auto& c : color_BG) {
    c = RGB(0xFF, 0xDA, 0x90);
  }
}

BOOL Cls_OnInitDialog(HWND hwnd, HWND hwnd_forcus, LPARAM lp) {
  (void)hwnd_forcus;
  (void)lp;
  (void)hwnd;

  // The icon is loaded.
  HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE);
  SendMessage(hwnd, WM_SETICON, ICON_BIG,
              (LPARAM)LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1)));

  // Edit control for test interface.
  out_edit.reset(new mk::Edit(GetDlgItem(hwnd, IDC_EDIT_OUTPUT)));
  in_edit.reset(new mk::Edit(GetDlgItem(hwnd, IDC_EDIT_INPUT)));
  row_edit.reset(new mk::Edit(GetDlgItem(hwnd, IDC_EDIT_SETROW)));
  col_edit.reset(new mk::Edit(GetDlgItem(hwnd, IDC_EDIT_SETCOL)));
  width_edit.reset(new mk::Edit(GetDlgItem(hwnd, IDC_EDIT_SETWIDTH)));
  select_edit.reset(new mk::Edit(GetDlgItem(hwnd, IDC_EDIT_SETSELECT)));

  // List view for test.
  mk::ListView::EnableListView();
  list_view.reset(new mk::ListView(GetDlgItem(hwnd, IDC_LIST1),
                                   mk::ListView::MODE::REPORT, row_max,
                                   col_max));
  ResetListViewForReportMode();

  return TRUE;
}

void Cls_OnDestroy(HWND hwnd) {
  (void)hwnd;
  PostQuitMessage(0);
  return;
}

void Cls_OnClose(HWND hwnd) {
  (void)hwnd;
  EndDialog(hwnd, TRUE);
  return;
}

void Cls_OnCommand(HWND hwnd, int id, HWND hWndCtl, UINT codeNotify) {
  (void)hwnd;
  (void)hWndCtl;
  (void)codeNotify;
  switch (id) {
    case IDLIST:
      ResetListViewForReportMode();
      break;
    case IDREPORT:
      // Reserved.
      out_edit->Add(L"Reserved\n");
      break;
    case IDICON:
      // Reserved.
      out_edit->Add(L"Reserved\n");
      break;
    case IDSMALLICON:
      // Reserved.
      out_edit->Add(L"Reserved\n");
      break;
    case IDCLEAR:
      out_edit->Add(L"Reserved\n");
      break;
    case IDCLEARALL:
      out_edit->Add(L"Reserved\n");
      break;
    case IDDELETE:
      out_edit->Add(L"Reserved\n");
      break;
    case IDDELETEALL:
      out_edit->Add(L"Reserved\n");
      break;
    case IDGETITEM:
      out_edit->Add(L"Reserved\n");
      break;
    case IDSETITEM:
      out_edit->Add(L"Reserved\n");
      break;
    case IDSETSIZE: {
      row_max = std::stoi(row_edit->Get());
      col_max = std::stoi(col_edit->Get());
      data_d.resize(row_max);
      data_f.resize(row_max);
      data_s.resize(row_max);
      color_FG.resize(row_max);
      color_BG.resize(row_max);
      // Debug string output.
      out_edit->Add(L"IDSETSIZE\n");
      out_edit->Add(L"row_max = %d, col_max = %d\n", row_max, col_max);
      out_edit->Add(L"\n");
      // Resize list view.
      list_view->Resize(mk::ListView::MODE::REPORT, row_max, col_max);
    } break;
    case IDSETWIDTH: {
      int width = std::stoi(width_edit->Get());
      list_view->SetColumnWidth(0, width);
      // Debug string output.
      out_edit->Add(L"IDSETWIDTH\n");
      out_edit->Add(L"width = %d\n", width);
      out_edit->Add(L"\n");
      break;
    }
    case IDSETSELECT: {
      int item = std::stoi(select_edit->Get());
      if ((item < 0) || (item > row_max)) {
        out_edit->Add(L"Invalid range\n");
        break;
      }
      list_view->SelectItem(item);
      // Debug string output.
      out_edit->Add(L"IDSETSELECT\n");
      out_edit->Add(L"item = %d\n", item);
      out_edit->Add(L"\n");
    } break;
    default:
      // none.
      break;
  }
  return;
}

LRESULT OnNofity(HWND hwndDlg, NMHDR* nmhdr) {
  assert(nmhdr);
  // if (nmhdr->hwndFrom == list_view->GetHandle()) {  // Access violation.
  if (nmhdr->hwndFrom == GetDlgItem(hwndDlg, IDC_LIST1)) {
    switch (nmhdr->code) {
      case LVN_COLUMNCLICK: {
        LPNMLISTVIEW lv = (LPNMLISTVIEW)nmhdr;
        // Debug string output.
        out_edit->Add(L"LVN_COLUMNCLICK\n");
        out_edit->Add(L"column = %d\n", lv->iSubItem);
        out_edit->Add(L"\n");
      } break;
      case NM_CLICK: {
        LPNMLISTVIEW lv = (LPNMLISTVIEW)nmhdr;
        // Debug string output.
        select_edit->Set(L"%d", lv->iItem);
        out_edit->Add(L"NM_CLICK\n");
        out_edit->Add(L"item = %d\n", lv->iItem);
        out_edit->Add(L"\n");
      } break;
      case NM_DBLCLK: {
        LPNMLISTVIEW lv = (LPNMLISTVIEW)nmhdr;
        // Debug string output.
        select_edit->Set(L"%d", lv->iItem);
        out_edit->Add(L"NM_DBLCLK\n");
        out_edit->Add(L"item = %d\n", lv->iItem);
        out_edit->Add(L"\n");
      } break;
      case NM_CUSTOMDRAW: {
        LPNMLVCUSTOMDRAW draw = (LPNMLVCUSTOMDRAW)nmhdr;
        switch (draw->nmcd.dwDrawStage) {
          case CDDS_PREPAINT:
            // Debug string output.
            out_edit->Add(L"CDDS_PREPAINT\n");
            // Use custom draw notification.
            SetWindowLong(hwndDlg, DWL_MSGRESULT, (LONG)CDRF_NOTIFYITEMDRAW);
            break;
          case CDDS_ITEMPREPAINT:
            assert(color_FG.size() >= draw->nmcd.dwItemSpec);
            assert(color_BG.size() >= draw->nmcd.dwItemSpec);
            draw->clrText = color_FG[draw->nmcd.dwItemSpec];
            draw->clrTextBk = color_BG[draw->nmcd.dwItemSpec];
            // Debug string output.
            out_edit->Add(L"CDDS_ITEMPREPAINT\n");
            // Use custom draw notification.
            SetWindowLong(hwndDlg, DWL_MSGRESULT, (LONG)CDRF_NEWFONT);
            break;
          default:
            // none.
            break;
        }
      }
      default:
        // none.
        break;
    }
  }
  return TRUE;
}

INT_PTR CALLBACK DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,
                            LPARAM lParam) {
  switch (uMsg) {
    HANDLE_DLG_MSG(hwndDlg, WM_INITDIALOG, Cls_OnInitDialog);
    HANDLE_DLG_MSG(hwndDlg, WM_DESTROY, Cls_OnDestroy);
    HANDLE_DLG_MSG(hwndDlg, WM_CLOSE, Cls_OnClose);
    HANDLE_DLG_MSG(hwndDlg, WM_COMMAND, Cls_OnCommand);
    case WM_NOTIFY:
      return OnNofity(hwndDlg, (NMHDR*)lParam);
    default:
      return FALSE;
  }
}

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    LPTSTR lpsCmdLine, int nCmdShow) {
  (void)hPrevInstance;
  (void)lpsCmdLine;
  (void)nCmdShow;

  DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), nullptr, &DialogProc,
                 NULL);
  return 0;
}
<|endoftext|>


<commit_before>/* LICENSE NOTICE
	Copyright (c) 2009, Frederick Emmott <mail@fredemmott.co.uk>

	Permission to use, copy, modify, and/or distribute this software for any
	purpose with or without fee is hereby granted, provided that the above
	copyright notice and this permission notice appear in all copies.

	THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
	WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
	MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
	ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
	WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
	ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
	OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "DebugHandler.h"

#include <QByteArray>
#include <QCoreApplication>
#include <QDebug>

#include <syslog.h>

namespace FastCgiQt
{
	DebugHandler::DebugHandler(QObject* parent)
		:
			QObject(parent)
	{
		qInstallMsgHandler(syslogHandler);
	}

	void DebugHandler::syslogHandler(QtMsgType type, const char* message)
	{
		::openlog(QCoreApplication::applicationName().toUtf8(), LOG_PERROR | LOG_PID, LOG_USER);
		switch(type)
		{
			case QtDebugMsg:
				::syslog(LOG_DEBUG, "DEBUG: %s", message);
				break;
			case QtWarningMsg:
				::syslog(LOG_WARNING, "WARNING: %s", message);
				break;
			case QtCriticalMsg:
				::syslog(LOG_CRIT, "CRITICAL: %s", message);
				break;
			case QtFatalMsg:
				::syslog(LOG_EMERG, "FATAL: %s", message);
				abort();
			default:
				::syslog(LOG_EMERG, "UNKNOWN: %s", message);
				abort();
		}
		::closelog();
	}

	DebugHandler::~DebugHandler()
	{
		qInstallMsgHandler(m_oldHandler);
	}
}
<commit_msg>cache application name for duration of debug message output - threading issue<commit_after>/* LICENSE NOTICE
	Copyright (c) 2009, Frederick Emmott <mail@fredemmott.co.uk>

	Permission to use, copy, modify, and/or distribute this software for any
	purpose with or without fee is hereby granted, provided that the above
	copyright notice and this permission notice appear in all copies.

	THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
	WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
	MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
	ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
	WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
	ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
	OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "DebugHandler.h"

#include <QByteArray>
#include <QCoreApplication>
#include <QDebug>

#include <syslog.h>

namespace FastCgiQt
{
	DebugHandler::DebugHandler(QObject* parent)
		:
			QObject(parent)
	{
		qInstallMsgHandler(syslogHandler);
	}

	void DebugHandler::syslogHandler(QtMsgType type, const char* message)
	{
		QByteArray name = QCoreApplication::applicationName().toUtf8();
		::openlog(name, LOG_PERROR | LOG_PID, LOG_USER);
		switch(type)
		{
			case QtDebugMsg:
				::syslog(LOG_DEBUG, "DEBUG: %s", message);
				break;
			case QtWarningMsg:
				::syslog(LOG_WARNING, "WARNING: %s", message);
				break;
			case QtCriticalMsg:
				::syslog(LOG_CRIT, "CRITICAL: %s", message);
				break;
			case QtFatalMsg:
				::syslog(LOG_EMERG, "FATAL: %s", message);
				abort();
			default:
				::syslog(LOG_EMERG, "UNKNOWN: %s", message);
				abort();
		}
		::closelog();
	}

	DebugHandler::~DebugHandler()
	{
		qInstallMsgHandler(m_oldHandler);
	}
}
<|endoftext|>


<commit_before>//===- Profile.cpp - XRay Profile Abstraction -----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Defines the XRay Profile class representing the latency profile generated by
// XRay's profiling mode.
//
//===----------------------------------------------------------------------===//
#include "llvm/XRay/Profile.h"

#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/XRay/Trace.h"
#include <deque>
#include <memory>

namespace llvm {
namespace xray {

namespace {

struct BlockHeader {
  uint32_t Size;
  uint32_t Number;
  uint64_t Thread;
};

static Expected<BlockHeader> readBlockHeader(DataExtractor &Extractor,
                                             uint32_t &Offset) {
  BlockHeader H;
  uint32_t CurrentOffset = Offset;
  H.Size = Extractor.getU32(&Offset);
  if (Offset == CurrentOffset)
    return make_error<StringError>(
        Twine("Error parsing block header size at offset '") +
            Twine(CurrentOffset) + "'",
        std::make_error_code(std::errc::invalid_argument));
  CurrentOffset = Offset;
  H.Number = Extractor.getU32(&Offset);
  if (Offset == CurrentOffset)
    return make_error<StringError>(
        Twine("Error parsing block header number at offset '") +
            Twine(CurrentOffset) + "'",
        std::make_error_code(std::errc::invalid_argument));
  CurrentOffset = Offset;
  H.Thread = Extractor.getU64(&Offset);
  if (Offset == CurrentOffset)
    return make_error<StringError>(
        Twine("Error parsing block header thread id at offset '") +
            Twine(CurrentOffset) + "'",
        std::make_error_code(std::errc::invalid_argument));
  return H;
}

static Expected<std::vector<Profile::FuncID>> readPath(DataExtractor &Extractor,
                                                       uint32_t &Offset) {
  // We're reading a sequence of int32_t's until we find a 0.
  std::vector<Profile::FuncID> Path;
  auto CurrentOffset = Offset;
  int32_t FuncId;
  do {
    FuncId = Extractor.getSigned(&Offset, 4);
    if (CurrentOffset == Offset)
      return make_error<StringError>(
          Twine("Error parsing path at offset '") + Twine(CurrentOffset) + "'",
          std::make_error_code(std::errc::invalid_argument));
    CurrentOffset = Offset;
    Path.push_back(FuncId);
  } while (FuncId != 0);
  return std::move(Path);
}

static Expected<Profile::Data> readData(DataExtractor &Extractor,
                                        uint32_t &Offset) {
  // We expect a certain number of elements for Data:
  //   - A 64-bit CallCount
  //   - A 64-bit CumulativeLocalTime counter
  Profile::Data D;
  auto CurrentOffset = Offset;
  D.CallCount = Extractor.getU64(&Offset);
  if (CurrentOffset == Offset)
    return make_error<StringError>(
        Twine("Error parsing call counts at offset '") + Twine(CurrentOffset) +
            "'",
        std::make_error_code(std::errc::invalid_argument));
  CurrentOffset = Offset;
  D.CumulativeLocalTime = Extractor.getU64(&Offset);
  if (CurrentOffset == Offset)
    return make_error<StringError>(
        Twine("Error parsing cumulative local time at offset '") +
            Twine(CurrentOffset) + "'",
        std::make_error_code(std::errc::invalid_argument));
  return D;
}

} // namespace

Error Profile::addBlock(Block &&B) {
  if (B.PathData.empty())
    return make_error<StringError>(
        "Block may not have empty path data.",
        std::make_error_code(std::errc::invalid_argument));

  Blocks.emplace_back(std::move(B));
  return Error::success();
}

Expected<std::vector<Profile::FuncID>> Profile::expandPath(PathID P) const {
  auto It = PathIDMap.find(P);
  if (It == PathIDMap.end())
    return make_error<StringError>(
        Twine("PathID not found: ") + Twine(P),
        std::make_error_code(std::errc::invalid_argument));
  std::vector<Profile::FuncID> Path;
  for (auto Node = It->second; Node; Node = Node->Caller)
    Path.push_back(Node->Func);
  return std::move(Path);
}

Profile::PathID Profile::internPath(ArrayRef<FuncID> P) {
  if (P.empty())
    return 0;

  auto RootToLeafPath = reverse(P);

  // Find the root.
  auto It = RootToLeafPath.begin();
  auto PathRoot = *It++;
  auto RootIt =
      find_if(Roots, [PathRoot](TrieNode *N) { return N->Func == PathRoot; });

  // If we've not seen this root before, remember it.
  TrieNode *Node = nullptr;
  if (RootIt == Roots.end()) {
    NodeStorage.emplace_back();
    Node = &NodeStorage.back();
    Node->Func = PathRoot;
    Roots.push_back(Node);
  } else {
    Node = *RootIt;
  }

  // Now traverse the path, re-creating if necessary.
  while (It != RootToLeafPath.end()) {
    auto NodeFuncID = *It++;
    auto CalleeIt = find_if(Node->Callees, [NodeFuncID](TrieNode *N) {
      return N->Func == NodeFuncID;
    });
    if (CalleeIt == Node->Callees.end()) {
      NodeStorage.emplace_back();
      auto NewNode = &NodeStorage.back();
      NewNode->Func = NodeFuncID;
      NewNode->Caller = Node;
      Node->Callees.push_back(NewNode);
      Node = NewNode;
    } else {
      Node = *CalleeIt;
    }
  }

  // At this point, Node *must* be pointing at the leaf.
  assert(Node->Func == P.front());
  if (Node->ID == 0) {
    Node->ID = NextID++;
    PathIDMap.insert({Node->ID, Node});
  }
  return Node->ID;
}

Profile mergeProfilesByThread(const Profile &L, const Profile &R) {
  Profile Merged;
  using PathDataMap = DenseMap<Profile::PathID, Profile::Data>;
  using PathDataMapPtr = std::unique_ptr<PathDataMap>;
  using PathDataVector = decltype(Profile::Block::PathData);
  using ThreadProfileIndexMap = DenseMap<Profile::ThreadID, PathDataMapPtr>;
  ThreadProfileIndexMap ThreadProfileIndex;

  for (const auto &P : {std::ref(L), std::ref(R)})
    for (const auto &Block : P.get()) {
      ThreadProfileIndexMap::iterator It;
      std::tie(It, std::ignore) = ThreadProfileIndex.insert(
          {Block.Thread, PathDataMapPtr{new PathDataMap()}});
      for (const auto &PathAndData : Block.PathData) {
        auto &PathID = PathAndData.first;
        auto &Data = PathAndData.second;
        auto NewPathID =
            Merged.internPath(cantFail(P.get().expandPath(PathID)));
        PathDataMap::iterator PathDataIt;
        bool Inserted;
        std::tie(PathDataIt, Inserted) = It->second->insert({NewPathID, Data});
        if (!Inserted) {
          auto &ExistingData = PathDataIt->second;
          ExistingData.CallCount += Data.CallCount;
          ExistingData.CumulativeLocalTime += Data.CumulativeLocalTime;
        }
      }
    }

  for (const auto &IndexedThreadBlock : ThreadProfileIndex) {
    PathDataVector PathAndData;
    PathAndData.reserve(IndexedThreadBlock.second->size());
    copy(*IndexedThreadBlock.second, std::back_inserter(PathAndData));
    cantFail(
        Merged.addBlock({IndexedThreadBlock.first, std::move(PathAndData)}));
  }
  return Merged;
}

Profile mergeProfilesByStack(const Profile &L, const Profile &R) {
  Profile Merged;
  using PathDataMap = DenseMap<Profile::PathID, Profile::Data>;
  PathDataMap PathData;
  using PathDataVector = decltype(Profile::Block::PathData);
  for (const auto &P : {std::ref(L), std::ref(R)})
    for (const auto &Block : P.get())
      for (const auto &PathAndData : Block.PathData) {
        auto &PathId = PathAndData.first;
        auto &Data = PathAndData.second;
        auto NewPathID =
            Merged.internPath(cantFail(P.get().expandPath(PathId)));
        PathDataMap::iterator PathDataIt;
        bool Inserted;
        std::tie(PathDataIt, Inserted) = PathData.insert({NewPathID, Data});
        if (!Inserted) {
          auto &ExistingData = PathDataIt->second;
          ExistingData.CallCount += Data.CallCount;
          ExistingData.CumulativeLocalTime += Data.CumulativeLocalTime;
        }
      }

  // In the end there's a single Block, for thread 0.
  PathDataVector Block;
  Block.reserve(PathData.size());
  copy(PathData, std::back_inserter(Block));
  cantFail(Merged.addBlock({0, std::move(Block)}));
  return Merged;
}

Expected<Profile> loadProfile(StringRef Filename) {
  int Fd;
  if (auto EC = sys::fs::openFileForRead(Filename, Fd))
    return make_error<StringError>(
        Twine("Cannot read profile from '") + Filename + "'", EC);

  uint64_t FileSize;
  if (auto EC = sys::fs::file_size(Filename, FileSize))
    return make_error<StringError>(
        Twine("Cannot get filesize of '") + Filename + "'", EC);

  std::error_code EC;
  sys::fs::mapped_file_region MappedFile(
      Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC);
  if (EC)
    return make_error<StringError>(
        Twine("Cannot mmap profile '") + Filename + "'", EC);
  StringRef Data(MappedFile.data(), MappedFile.size());

  Profile P;
  uint32_t Offset = 0;
  DataExtractor Extractor(Data, true, 8);

  // For each block we get from the file:
  while (Offset != MappedFile.size()) {
    auto HeaderOrError = readBlockHeader(Extractor, Offset);
    if (!HeaderOrError)
      return HeaderOrError.takeError();

    // TODO: Maybe store this header information for each block, even just for
    // debugging?
    const auto &Header = HeaderOrError.get();

    // Read in the path data.
    auto PathOrError = readPath(Extractor, Offset);
    if (!PathOrError)
      return PathOrError.takeError();
    const auto &Path = PathOrError.get();

    // For each path we encounter, we should intern it to get a PathID.
    auto DataOrError = readData(Extractor, Offset);
    if (!DataOrError)
      return DataOrError.takeError();
    auto &Data = DataOrError.get();

    if (auto E =
            P.addBlock(Profile::Block{Profile::ThreadID{Header.Thread},
                                      {{P.internPath(Path), std::move(Data)}}}))
      return std::move(E);
  }

  return std::move(P);
}

namespace {

struct StackEntry {
  uint64_t Timestamp;
  Profile::FuncID FuncId;
};

} // namespace

Expected<Profile> profileFromTrace(const Trace &T) {
  Profile P;

  // The implementation of the algorithm re-creates the execution of
  // the functions based on the trace data. To do this, we set up a number of
  // data structures to track the execution context of every thread in the
  // Trace.
  DenseMap<Profile::ThreadID, std::vector<StackEntry>> ThreadStacks;
  DenseMap<Profile::ThreadID, DenseMap<Profile::PathID, Profile::Data>>
      ThreadPathData;

  //  We then do a pass through the Trace to account data on a per-thread-basis.
  for (const auto &E : T) {
    auto &TSD = ThreadStacks[E.TId];
    switch (E.Type) {
    case RecordTypes::ENTER:
    case RecordTypes::ENTER_ARG:

      // Push entries into the function call stack.
      TSD.push_back({E.TSC, E.FuncId});
      break;

    case RecordTypes::EXIT:
    case RecordTypes::TAIL_EXIT:

      // Exits cause some accounting to happen, based on the state of the stack.
      // For each function we pop off the stack, we take note of the path and
      // record the cumulative state for this path. As we're doing this, we
      // intern the path into the Profile.
      while (!TSD.empty()) {
        auto Top = TSD.back();
        auto FunctionLocalTime = AbsoluteDifference(Top.Timestamp, E.TSC);
        SmallVector<Profile::FuncID, 16> Path;
        transform(reverse(TSD), std::back_inserter(Path),
                  std::mem_fn(&StackEntry::FuncId));
        auto InternedPath = P.internPath(Path);
        auto &TPD = ThreadPathData[E.TId][InternedPath];
        ++TPD.CallCount;
        TPD.CumulativeLocalTime += FunctionLocalTime;
        TSD.pop_back();

        // If we've matched the corresponding entry event for this function,
        // then we exit the loop.
        if (Top.FuncId == E.FuncId)
          break;

        // FIXME: Consider the intermediate times and the cumulative tree time
        // as well.
      }

      break;
    }
  }

  // Once we've gone through the Trace, we now create one Block per thread in
  // the Profile.
  for (const auto &ThreadPaths : ThreadPathData) {
    const auto &TID = ThreadPaths.first;
    const auto &PathsData = ThreadPaths.second;
    if (auto E = P.addBlock({
            TID,
            std::vector<std::pair<Profile::PathID, Profile::Data>>(
                PathsData.begin(), PathsData.end()),
        }))
      return std::move(E);
  }

  return P;
}

} // namespace xray
} // namespace llvm
<commit_msg>[XRay] fixup: add one more missing std::move(...)<commit_after>//===- Profile.cpp - XRay Profile Abstraction -----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Defines the XRay Profile class representing the latency profile generated by
// XRay's profiling mode.
//
//===----------------------------------------------------------------------===//
#include "llvm/XRay/Profile.h"

#include "llvm/Support/DataExtractor.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/XRay/Trace.h"
#include <deque>
#include <memory>

namespace llvm {
namespace xray {

namespace {

struct BlockHeader {
  uint32_t Size;
  uint32_t Number;
  uint64_t Thread;
};

static Expected<BlockHeader> readBlockHeader(DataExtractor &Extractor,
                                             uint32_t &Offset) {
  BlockHeader H;
  uint32_t CurrentOffset = Offset;
  H.Size = Extractor.getU32(&Offset);
  if (Offset == CurrentOffset)
    return make_error<StringError>(
        Twine("Error parsing block header size at offset '") +
            Twine(CurrentOffset) + "'",
        std::make_error_code(std::errc::invalid_argument));
  CurrentOffset = Offset;
  H.Number = Extractor.getU32(&Offset);
  if (Offset == CurrentOffset)
    return make_error<StringError>(
        Twine("Error parsing block header number at offset '") +
            Twine(CurrentOffset) + "'",
        std::make_error_code(std::errc::invalid_argument));
  CurrentOffset = Offset;
  H.Thread = Extractor.getU64(&Offset);
  if (Offset == CurrentOffset)
    return make_error<StringError>(
        Twine("Error parsing block header thread id at offset '") +
            Twine(CurrentOffset) + "'",
        std::make_error_code(std::errc::invalid_argument));
  return H;
}

static Expected<std::vector<Profile::FuncID>> readPath(DataExtractor &Extractor,
                                                       uint32_t &Offset) {
  // We're reading a sequence of int32_t's until we find a 0.
  std::vector<Profile::FuncID> Path;
  auto CurrentOffset = Offset;
  int32_t FuncId;
  do {
    FuncId = Extractor.getSigned(&Offset, 4);
    if (CurrentOffset == Offset)
      return make_error<StringError>(
          Twine("Error parsing path at offset '") + Twine(CurrentOffset) + "'",
          std::make_error_code(std::errc::invalid_argument));
    CurrentOffset = Offset;
    Path.push_back(FuncId);
  } while (FuncId != 0);
  return std::move(Path);
}

static Expected<Profile::Data> readData(DataExtractor &Extractor,
                                        uint32_t &Offset) {
  // We expect a certain number of elements for Data:
  //   - A 64-bit CallCount
  //   - A 64-bit CumulativeLocalTime counter
  Profile::Data D;
  auto CurrentOffset = Offset;
  D.CallCount = Extractor.getU64(&Offset);
  if (CurrentOffset == Offset)
    return make_error<StringError>(
        Twine("Error parsing call counts at offset '") + Twine(CurrentOffset) +
            "'",
        std::make_error_code(std::errc::invalid_argument));
  CurrentOffset = Offset;
  D.CumulativeLocalTime = Extractor.getU64(&Offset);
  if (CurrentOffset == Offset)
    return make_error<StringError>(
        Twine("Error parsing cumulative local time at offset '") +
            Twine(CurrentOffset) + "'",
        std::make_error_code(std::errc::invalid_argument));
  return D;
}

} // namespace

Error Profile::addBlock(Block &&B) {
  if (B.PathData.empty())
    return make_error<StringError>(
        "Block may not have empty path data.",
        std::make_error_code(std::errc::invalid_argument));

  Blocks.emplace_back(std::move(B));
  return Error::success();
}

Expected<std::vector<Profile::FuncID>> Profile::expandPath(PathID P) const {
  auto It = PathIDMap.find(P);
  if (It == PathIDMap.end())
    return make_error<StringError>(
        Twine("PathID not found: ") + Twine(P),
        std::make_error_code(std::errc::invalid_argument));
  std::vector<Profile::FuncID> Path;
  for (auto Node = It->second; Node; Node = Node->Caller)
    Path.push_back(Node->Func);
  return std::move(Path);
}

Profile::PathID Profile::internPath(ArrayRef<FuncID> P) {
  if (P.empty())
    return 0;

  auto RootToLeafPath = reverse(P);

  // Find the root.
  auto It = RootToLeafPath.begin();
  auto PathRoot = *It++;
  auto RootIt =
      find_if(Roots, [PathRoot](TrieNode *N) { return N->Func == PathRoot; });

  // If we've not seen this root before, remember it.
  TrieNode *Node = nullptr;
  if (RootIt == Roots.end()) {
    NodeStorage.emplace_back();
    Node = &NodeStorage.back();
    Node->Func = PathRoot;
    Roots.push_back(Node);
  } else {
    Node = *RootIt;
  }

  // Now traverse the path, re-creating if necessary.
  while (It != RootToLeafPath.end()) {
    auto NodeFuncID = *It++;
    auto CalleeIt = find_if(Node->Callees, [NodeFuncID](TrieNode *N) {
      return N->Func == NodeFuncID;
    });
    if (CalleeIt == Node->Callees.end()) {
      NodeStorage.emplace_back();
      auto NewNode = &NodeStorage.back();
      NewNode->Func = NodeFuncID;
      NewNode->Caller = Node;
      Node->Callees.push_back(NewNode);
      Node = NewNode;
    } else {
      Node = *CalleeIt;
    }
  }

  // At this point, Node *must* be pointing at the leaf.
  assert(Node->Func == P.front());
  if (Node->ID == 0) {
    Node->ID = NextID++;
    PathIDMap.insert({Node->ID, Node});
  }
  return Node->ID;
}

Profile mergeProfilesByThread(const Profile &L, const Profile &R) {
  Profile Merged;
  using PathDataMap = DenseMap<Profile::PathID, Profile::Data>;
  using PathDataMapPtr = std::unique_ptr<PathDataMap>;
  using PathDataVector = decltype(Profile::Block::PathData);
  using ThreadProfileIndexMap = DenseMap<Profile::ThreadID, PathDataMapPtr>;
  ThreadProfileIndexMap ThreadProfileIndex;

  for (const auto &P : {std::ref(L), std::ref(R)})
    for (const auto &Block : P.get()) {
      ThreadProfileIndexMap::iterator It;
      std::tie(It, std::ignore) = ThreadProfileIndex.insert(
          {Block.Thread, PathDataMapPtr{new PathDataMap()}});
      for (const auto &PathAndData : Block.PathData) {
        auto &PathID = PathAndData.first;
        auto &Data = PathAndData.second;
        auto NewPathID =
            Merged.internPath(cantFail(P.get().expandPath(PathID)));
        PathDataMap::iterator PathDataIt;
        bool Inserted;
        std::tie(PathDataIt, Inserted) = It->second->insert({NewPathID, Data});
        if (!Inserted) {
          auto &ExistingData = PathDataIt->second;
          ExistingData.CallCount += Data.CallCount;
          ExistingData.CumulativeLocalTime += Data.CumulativeLocalTime;
        }
      }
    }

  for (const auto &IndexedThreadBlock : ThreadProfileIndex) {
    PathDataVector PathAndData;
    PathAndData.reserve(IndexedThreadBlock.second->size());
    copy(*IndexedThreadBlock.second, std::back_inserter(PathAndData));
    cantFail(
        Merged.addBlock({IndexedThreadBlock.first, std::move(PathAndData)}));
  }
  return Merged;
}

Profile mergeProfilesByStack(const Profile &L, const Profile &R) {
  Profile Merged;
  using PathDataMap = DenseMap<Profile::PathID, Profile::Data>;
  PathDataMap PathData;
  using PathDataVector = decltype(Profile::Block::PathData);
  for (const auto &P : {std::ref(L), std::ref(R)})
    for (const auto &Block : P.get())
      for (const auto &PathAndData : Block.PathData) {
        auto &PathId = PathAndData.first;
        auto &Data = PathAndData.second;
        auto NewPathID =
            Merged.internPath(cantFail(P.get().expandPath(PathId)));
        PathDataMap::iterator PathDataIt;
        bool Inserted;
        std::tie(PathDataIt, Inserted) = PathData.insert({NewPathID, Data});
        if (!Inserted) {
          auto &ExistingData = PathDataIt->second;
          ExistingData.CallCount += Data.CallCount;
          ExistingData.CumulativeLocalTime += Data.CumulativeLocalTime;
        }
      }

  // In the end there's a single Block, for thread 0.
  PathDataVector Block;
  Block.reserve(PathData.size());
  copy(PathData, std::back_inserter(Block));
  cantFail(Merged.addBlock({0, std::move(Block)}));
  return Merged;
}

Expected<Profile> loadProfile(StringRef Filename) {
  int Fd;
  if (auto EC = sys::fs::openFileForRead(Filename, Fd))
    return make_error<StringError>(
        Twine("Cannot read profile from '") + Filename + "'", EC);

  uint64_t FileSize;
  if (auto EC = sys::fs::file_size(Filename, FileSize))
    return make_error<StringError>(
        Twine("Cannot get filesize of '") + Filename + "'", EC);

  std::error_code EC;
  sys::fs::mapped_file_region MappedFile(
      Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC);
  if (EC)
    return make_error<StringError>(
        Twine("Cannot mmap profile '") + Filename + "'", EC);
  StringRef Data(MappedFile.data(), MappedFile.size());

  Profile P;
  uint32_t Offset = 0;
  DataExtractor Extractor(Data, true, 8);

  // For each block we get from the file:
  while (Offset != MappedFile.size()) {
    auto HeaderOrError = readBlockHeader(Extractor, Offset);
    if (!HeaderOrError)
      return HeaderOrError.takeError();

    // TODO: Maybe store this header information for each block, even just for
    // debugging?
    const auto &Header = HeaderOrError.get();

    // Read in the path data.
    auto PathOrError = readPath(Extractor, Offset);
    if (!PathOrError)
      return PathOrError.takeError();
    const auto &Path = PathOrError.get();

    // For each path we encounter, we should intern it to get a PathID.
    auto DataOrError = readData(Extractor, Offset);
    if (!DataOrError)
      return DataOrError.takeError();
    auto &Data = DataOrError.get();

    if (auto E =
            P.addBlock(Profile::Block{Profile::ThreadID{Header.Thread},
                                      {{P.internPath(Path), std::move(Data)}}}))
      return std::move(E);
  }

  return std::move(P);
}

namespace {

struct StackEntry {
  uint64_t Timestamp;
  Profile::FuncID FuncId;
};

} // namespace

Expected<Profile> profileFromTrace(const Trace &T) {
  Profile P;

  // The implementation of the algorithm re-creates the execution of
  // the functions based on the trace data. To do this, we set up a number of
  // data structures to track the execution context of every thread in the
  // Trace.
  DenseMap<Profile::ThreadID, std::vector<StackEntry>> ThreadStacks;
  DenseMap<Profile::ThreadID, DenseMap<Profile::PathID, Profile::Data>>
      ThreadPathData;

  //  We then do a pass through the Trace to account data on a per-thread-basis.
  for (const auto &E : T) {
    auto &TSD = ThreadStacks[E.TId];
    switch (E.Type) {
    case RecordTypes::ENTER:
    case RecordTypes::ENTER_ARG:

      // Push entries into the function call stack.
      TSD.push_back({E.TSC, E.FuncId});
      break;

    case RecordTypes::EXIT:
    case RecordTypes::TAIL_EXIT:

      // Exits cause some accounting to happen, based on the state of the stack.
      // For each function we pop off the stack, we take note of the path and
      // record the cumulative state for this path. As we're doing this, we
      // intern the path into the Profile.
      while (!TSD.empty()) {
        auto Top = TSD.back();
        auto FunctionLocalTime = AbsoluteDifference(Top.Timestamp, E.TSC);
        SmallVector<Profile::FuncID, 16> Path;
        transform(reverse(TSD), std::back_inserter(Path),
                  std::mem_fn(&StackEntry::FuncId));
        auto InternedPath = P.internPath(Path);
        auto &TPD = ThreadPathData[E.TId][InternedPath];
        ++TPD.CallCount;
        TPD.CumulativeLocalTime += FunctionLocalTime;
        TSD.pop_back();

        // If we've matched the corresponding entry event for this function,
        // then we exit the loop.
        if (Top.FuncId == E.FuncId)
          break;

        // FIXME: Consider the intermediate times and the cumulative tree time
        // as well.
      }

      break;
    }
  }

  // Once we've gone through the Trace, we now create one Block per thread in
  // the Profile.
  for (const auto &ThreadPaths : ThreadPathData) {
    const auto &TID = ThreadPaths.first;
    const auto &PathsData = ThreadPaths.second;
    if (auto E = P.addBlock({
            TID,
            std::vector<std::pair<Profile::PathID, Profile::Data>>(
                PathsData.begin(), PathsData.end()),
        }))
      return std::move(E);
  }

  return std::move(P);
}

} // namespace xray
} // namespace llvm
<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_FUN_REP_MATRIX_HPP
#define STAN_MATH_REV_FUN_REP_MATRIX_HPP

#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/rev/core.hpp>
#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/rep_matrix.hpp>

namespace stan {
namespace math {

template <>
inline auto rep_matrix<double, var_value<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>>>(const double& x, int m, int n) {
  check_nonnegative("rep_matrix", "rows", m);
  check_nonnegative("rep_matrix", "cols", n);
  using eig_mat = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>;
  return var_value<eig_mat>(eig_mat::Constant(m, n, x));
}

template <>
inline auto rep_matrix<var, var_value<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>>>(const var& x, int m, int n) {
  check_nonnegative("rep_matrix", "rows", m);
  check_nonnegative("rep_matrix", "cols", n);
  using eig_mat = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>;
  return make_callback_var(eig_mat::Constant(m, n, x.val()), [x](auto& rep) mutable {
    x.adj() += rep.adj().sum();
  });
}

}  // namespace math
}  // namespace stan

#endif
<commit_msg>[Jenkins] auto-formatting by clang-format version 6.0.0-1ubuntu2~16.04.1 (tags/RELEASE_600/final)<commit_after>#ifndef STAN_MATH_REV_FUN_REP_MATRIX_HPP
#define STAN_MATH_REV_FUN_REP_MATRIX_HPP

#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/rev/core.hpp>
#include <stan/math/prim/meta.hpp>
#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/rep_matrix.hpp>

namespace stan {
namespace math {

template <>
inline auto rep_matrix<
    double, var_value<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>>>(
    const double& x, int m, int n) {
  check_nonnegative("rep_matrix", "rows", m);
  check_nonnegative("rep_matrix", "cols", n);
  using eig_mat = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>;
  return var_value<eig_mat>(eig_mat::Constant(m, n, x));
}

template <>
inline auto rep_matrix<
    var, var_value<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>>>(
    const var& x, int m, int n) {
  check_nonnegative("rep_matrix", "rows", m);
  check_nonnegative("rep_matrix", "cols", n);
  using eig_mat = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>;
  return make_callback_var(
      eig_mat::Constant(m, n, x.val()),
      [x](auto& rep) mutable { x.adj() += rep.adj().sum(); });
}

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before><commit_msg>fVal->nVal<commit_after><|endoftext|>