<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-2012 Francois Beaune, Jupiter Jazz Limited
//
// 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.
//

// Interface header.
#include "progressiveframerenderer.h"

// appleseed.renderer headers.
#include "renderer/kernel/rendering/progressive/samplecounter.h"
#include "renderer/kernel/rendering/progressive/samplegeneratorjob.h"
#include "renderer/kernel/rendering/accumulationframebuffer.h"
#include "renderer/kernel/rendering/framerendererbase.h"
#include "renderer/kernel/rendering/isamplegenerator.h"
#include "renderer/kernel/rendering/itilecallback.h"
#include "renderer/modeling/frame/frame.h"
#include "renderer/modeling/project/project.h"

// appleseed.foundation headers.
#include "foundation/image/analysis.h"
#include "foundation/image/canvasproperties.h"
#include "foundation/image/genericimagefilereader.h"
#include "foundation/image/image.h"
#include "foundation/math/fixedsizehistory.h"
#include "foundation/platform/thread.h"
#include "foundation/platform/timer.h"
#include "foundation/utility/foreach.h"
#include "foundation/utility/job.h"
#include "foundation/utility/maplefile.h"
#include "foundation/utility/searchpaths.h"
#include "foundation/utility/string.h"

// Standard headers.
#include <vector>

using namespace boost;
using namespace foundation;
using namespace std;

namespace renderer
{

namespace
{
    typedef vector<ISampleGenerator*> SampleGeneratorVector;
    typedef vector<ITileCallback*> TileCallbackVector;

    //
    // Progressive frame renderer.
    //

    class ProgressiveFrameRenderer
      : public FrameRendererBase
    {
      public:
        ProgressiveFrameRenderer(
            const Project&                  project,
            ISampleGeneratorFactory*        generator_factory,
            ITileCallbackFactory*           callback_factory,
            const ParamArray&               params)
          : m_frame(*project.get_frame())
          , m_params(params)
          , m_sample_counter(m_params.m_max_sample_count)
          , m_ref_image_avg_lum(0.0)
        {
            // We must have a generator factory, but it's OK not to have a callback factory.
            assert(generator_factory);

            // Create an accumulation framebuffer.
            const CanvasProperties& props = m_frame.image().properties();
            m_framebuffer.reset(
                generator_factory->create_accumulation_framebuffer(
                    props.m_canvas_width,
                    props.m_canvas_height));

            // Create and initialize the job manager.
            m_job_manager.reset(
                new JobManager(
                    global_logger(),
                    m_job_queue,
                    m_params.m_thread_count,
                    JobManager::KeepRunningOnEmptyQueue));

            // Instantiate sample generators, one per rendering thread.
            for (size_t i = 0; i < m_params.m_thread_count; ++i)
            {
                m_sample_generators.push_back(
                    generator_factory->create(i, m_params.m_thread_count));
            }

            // Instantiate tile callbacks, one per rendering thread.
            if (callback_factory)
            {
                for (size_t i = 0; i < m_params.m_thread_count; ++i)
                    m_tile_callbacks.push_back(callback_factory->create());
            }

            // Load the reference image if one is specified.
            if (!m_params.m_ref_image_path.empty())
            {
                const string ref_image_path =
                    project.get_search_paths().qualify(m_params.m_ref_image_path);

                RENDERER_LOG_DEBUG("loading reference image %s...", ref_image_path.c_str());

                GenericImageFileReader reader;
                m_ref_image.reset(reader.read(ref_image_path.c_str()));

                m_ref_image_avg_lum = compute_average_luminance(*m_ref_image.get());

                RENDERER_LOG_DEBUG(
                    "reference image average luminance is %s.",
                    pretty_scalar(m_ref_image_avg_lum, 6).c_str());
            }

            print_rendering_thread_count(m_params.m_thread_count);
        }

        virtual ~ProgressiveFrameRenderer()
        {
            // Tell the statistics printing thread to stop.
            m_abort_switch.abort();

            // Wait until the statistics printing thread is terminated.
            m_statistics_thread->join();

            // Delete tile callbacks.
            for (const_each<TileCallbackVector> i = m_tile_callbacks; i; ++i)
                (*i)->release();

            // Delete sample generators.
            for (const_each<SampleGeneratorVector> i = m_sample_generators; i; ++i)
                (*i)->release();
        }

        virtual void release()
        {
            delete this;
        }

        virtual void render()
        {
            start_rendering();
            m_job_queue.wait_until_completion();
        }

        virtual void start_rendering()
        {
            assert(!is_rendering());
            assert(!m_job_queue.has_scheduled_or_running_jobs());

            m_abort_switch.clear();
            m_framebuffer->clear();
            m_sample_counter.clear();

            // Reset sample generators.
            for (size_t i = 0; i < m_params.m_thread_count; ++i)
                m_sample_generators[i]->reset();

            // Schedule the first batch of jobs.
            for (size_t i = 0; i < m_params.m_thread_count; ++i)
            {
                m_job_queue.schedule(
                    new SampleGeneratorJob(
                        m_frame,
                        *m_framebuffer.get(),
                        m_sample_generators[i],
                        m_sample_counter,
                        m_tile_callbacks[i],
                        m_job_queue,
                        i,                              // job index
                        m_params.m_thread_count,        // job count
                        0,                              // pass number
                        m_abort_switch));
            }

            // Start job execution.
            m_job_manager->start();

            // Create and start the statistics printing thread.
            m_statistics_func.reset(
                new StatisticsFunc(
                    m_frame,
                    *m_framebuffer.get(),
                    m_params.m_print_luminance_stats,
                    m_ref_image.get(),
                    m_ref_image_avg_lum,
                    m_abort_switch));
            ThreadFunctionWrapper<StatisticsFunc> wrapper(m_statistics_func.get());
            m_statistics_thread.reset(new thread(wrapper));
        }

        virtual void stop_rendering()
        {
            // Tell rendering jobs and the statistics printing thread to stop.
            m_abort_switch.abort();

            // Stop job execution.
            m_job_manager->stop();

            // Delete all non-executed jobs.
            m_job_queue.clear_scheduled_jobs();

            // Wait until the statistics printing thread is terminated.
            m_statistics_thread->join();
        }

        virtual void terminate_rendering()
        {
            stop_rendering();

            m_statistics_func->write_rms_deviation_file();
        }

        virtual bool is_rendering() const
        {
            return m_job_queue.has_scheduled_or_running_jobs();
        }

      private:
        struct Parameters
        {
            const size_t    m_thread_count;             // number of rendering threads
            const uint64    m_max_sample_count;         // maximum total number of samples to store in the framebuffer
            const bool      m_print_luminance_stats;    // compute and print luminance statistics?
            const string    m_ref_image_path;           // path to the reference image

            // Constructor, extract parameters.
            explicit Parameters(const ParamArray& params)
              : m_thread_count(FrameRendererBase::get_rendering_thread_count(params))
              , m_max_sample_count(params.get_optional<uint64>("max_samples", numeric_limits<uint64>::max()))
              , m_print_luminance_stats(params.get_optional<bool>("print_luminance_statistics", false))
              , m_ref_image_path(params.get_optional<string>("reference_image", ""))
            {
            }
        };

        Frame&                              m_frame;
        const Parameters                    m_params;
        SampleCounter                       m_sample_counter;

        auto_ptr<AccumulationFramebuffer>   m_framebuffer;

        JobQueue                            m_job_queue;
        auto_ptr<JobManager>                m_job_manager;
        AbortSwitch                         m_abort_switch;

        SampleGeneratorVector               m_sample_generators;
        TileCallbackVector                  m_tile_callbacks;

        auto_ptr<Image>                     m_ref_image;
        double                              m_ref_image_avg_lum;

        class StatisticsFunc
          : public NonCopyable
        {
          public:
            StatisticsFunc(
                Frame&                      frame,
                AccumulationFramebuffer&    framebuffer,
                const bool                  print_luminance_stats,
                const Image*                ref_image,
                const double                ref_image_avg_lum,
                AbortSwitch&                abort_switch)
              : m_frame(frame)
              , m_framebuffer(framebuffer)
              , m_print_luminance_stats(print_luminance_stats)
              , m_ref_image(ref_image)
              , m_ref_image_avg_lum(ref_image_avg_lum)
              , m_abort_switch(abort_switch)
              , m_timer_frequency(m_timer.frequency())
              , m_last_time(m_timer.read())
              , m_last_sample_count(0)
            {
            }

            void operator()()
            {
                while (!m_abort_switch.is_aborted())
                {
                    const uint64 time = m_timer.read();
                    const uint64 elapsed_ticks = time - m_last_time;
                    const double elapsed_seconds = static_cast<double>(elapsed_ticks) / m_timer_frequency;

                    if (elapsed_seconds >= 1.0)
                    {
                        print_and_record_statistics(elapsed_seconds);
                        m_last_time = time;
                    }

                    foundation::sleep(5);   // needs full qualification
                }
            }

            void write_rms_deviation_file() const
            {
                if (!m_spp_count_history.empty())
                {
                    MapleFile file("RMS Deviation.mpl");
                    file.define("rmsd", m_spp_count_history, m_rmsd_history);
                    file.plot("rmsd", "RMS Deviation");
                }
            }

          private:
            Frame&                          m_frame;
            AccumulationFramebuffer&        m_framebuffer;
            const bool                      m_print_luminance_stats;
            const Image*                    m_ref_image;
            const double                    m_ref_image_avg_lum;
            AbortSwitch&                    m_abort_switch;

            DefaultWallclockTimer           m_timer;
            uint64                          m_timer_frequency;
            uint64                          m_last_time;

            uint64                          m_last_sample_count;
            FixedSizeHistory<double, 16>    m_sps_count_history;    // samples per second history
            vector<double>                  m_spp_count_history;    // samples per pixel history
            vector<double>                  m_rmsd_history;         // RMS deviation history

            void print_and_record_statistics(const double elapsed_seconds)
            {
                print_performance_statistics(elapsed_seconds);

                if (m_print_luminance_stats || m_ref_image)
                    print_and_record_convergence_statistics();
            }

            void print_performance_statistics(const double elapsed_seconds)
            {
                const uint64 new_sample_count = m_framebuffer.get_sample_count();
                const uint64 pixel_count = static_cast<uint64>(m_frame.image().properties().m_pixel_count);
                const double spp_count = static_cast<double>(new_sample_count) / pixel_count;
                const double sps_count = static_cast<double>(new_sample_count - m_last_sample_count) / elapsed_seconds;

                m_sps_count_history.insert(sps_count);

                const uint64 avg_sps_count = truncate<uint64>(m_sps_count_history.compute_average());

                RENDERER_LOG_INFO(
                    "%s samples, %s samples/pixel, %s samples/second",
                    pretty_uint(new_sample_count).c_str(),
                    pretty_scalar(spp_count).c_str(),
                    pretty_uint(avg_sps_count).c_str());

                m_last_sample_count = new_sample_count;
            }

            void print_and_record_convergence_statistics()
            {
                assert(m_print_luminance_stats || m_ref_image);

                string output;

                Image current_image(m_frame.image());
                m_frame.transform_to_output_color_space(current_image);

                if (m_print_luminance_stats)
                {
                    const double avg_lum = compute_average_luminance(current_image);
                    output += "average luminance " + pretty_scalar(avg_lum, 6);

                    if (m_ref_image)
                    {
                        const double avg_lum_delta = abs(m_ref_image_avg_lum - avg_lum);
                        output += " (";
                        output += pretty_percent(avg_lum_delta, m_ref_image_avg_lum, 3);
                        output += " error)";
                    }
                }

                if (m_ref_image)
                {
                    if (m_print_luminance_stats)
                        output += ", ";

                    const double spp_count =
                          static_cast<double>(m_framebuffer.get_sample_count())
                        / m_frame.image().properties().m_pixel_count;

                    const double rmsd = compute_rms_deviation(current_image, *m_ref_image);

                    output += "rms deviation " + pretty_scalar(rmsd, 6);

                    m_spp_count_history.push_back(spp_count);
                    m_rmsd_history.push_back(rmsd);
                }

                RENDERER_LOG_DEBUG("%s", output.c_str());
            }
        };

        auto_ptr<StatisticsFunc>            m_statistics_func;
        auto_ptr<thread>                    m_statistics_thread;
    };
}

//
// ProgressiveFrameRendererFactory class implementation.
//

ProgressiveFrameRendererFactory::ProgressiveFrameRendererFactory(
    const Project&              project,
    ISampleGeneratorFactory*    generator_factory,
    ITileCallbackFactory*       callback_factory,
    const ParamArray&           params)
  : m_project(project)
  , m_generator_factory(generator_factory)
  , m_callback_factory(callback_factory)
  , m_params(params)
{
}

void ProgressiveFrameRendererFactory::release()
{
    delete this;
}

IFrameRenderer* ProgressiveFrameRendererFactory::create()
{
    return
        new ProgressiveFrameRenderer(
            m_project,
            m_generator_factory,
            m_callback_factory,
            m_params);
}

IFrameRenderer* ProgressiveFrameRendererFactory::create(
    const Project&              project,
    ISampleGeneratorFactory*    generator_factory,
    ITileCallbackFactory*       callback_factory,
    const ParamArray&           params)
{
    return
        new ProgressiveFrameRenderer(
            project,
            generator_factory,
            callback_factory,
            params);
}

}   // namespace renderer
<commit_msg>minor code tweaks.<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-2012 Francois Beaune, Jupiter Jazz Limited
//
// 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.
//

// Interface header.
#include "progressiveframerenderer.h"

// appleseed.renderer headers.
#include "renderer/kernel/rendering/progressive/samplecounter.h"
#include "renderer/kernel/rendering/progressive/samplegeneratorjob.h"
#include "renderer/kernel/rendering/accumulationframebuffer.h"
#include "renderer/kernel/rendering/framerendererbase.h"
#include "renderer/kernel/rendering/isamplegenerator.h"
#include "renderer/kernel/rendering/itilecallback.h"
#include "renderer/modeling/frame/frame.h"
#include "renderer/modeling/project/project.h"

// appleseed.foundation headers.
#include "foundation/image/analysis.h"
#include "foundation/image/canvasproperties.h"
#include "foundation/image/genericimagefilereader.h"
#include "foundation/image/image.h"
#include "foundation/math/fixedsizehistory.h"
#include "foundation/platform/thread.h"
#include "foundation/platform/timer.h"
#include "foundation/utility/foreach.h"
#include "foundation/utility/job.h"
#include "foundation/utility/maplefile.h"
#include "foundation/utility/searchpaths.h"
#include "foundation/utility/string.h"

// Standard headers.
#include <vector>

using namespace boost;
using namespace foundation;
using namespace std;

namespace renderer
{

namespace
{
    typedef vector<ISampleGenerator*> SampleGeneratorVector;
    typedef vector<ITileCallback*> TileCallbackVector;

    //
    // Progressive frame renderer.
    //

    class ProgressiveFrameRenderer
      : public FrameRendererBase
    {
      public:
        ProgressiveFrameRenderer(
            const Project&                  project,
            ISampleGeneratorFactory*        generator_factory,
            ITileCallbackFactory*           callback_factory,
            const ParamArray&               params)
          : m_frame(*project.get_frame())
          , m_params(params)
          , m_sample_counter(m_params.m_max_sample_count)
          , m_ref_image_avg_lum(0.0)
        {
            // We must have a generator factory, but it's OK not to have a callback factory.
            assert(generator_factory);

            // Create an accumulation framebuffer.
            const CanvasProperties& props = m_frame.image().properties();
            m_framebuffer.reset(
                generator_factory->create_accumulation_framebuffer(
                    props.m_canvas_width,
                    props.m_canvas_height));

            // Create and initialize the job manager.
            m_job_manager.reset(
                new JobManager(
                    global_logger(),
                    m_job_queue,
                    m_params.m_thread_count,
                    JobManager::KeepRunningOnEmptyQueue));

            // Instantiate sample generators, one per rendering thread.
            for (size_t i = 0; i < m_params.m_thread_count; ++i)
            {
                m_sample_generators.push_back(
                    generator_factory->create(i, m_params.m_thread_count));
            }

            // Instantiate tile callbacks, one per rendering thread.
            if (callback_factory)
            {
                for (size_t i = 0; i < m_params.m_thread_count; ++i)
                    m_tile_callbacks.push_back(callback_factory->create());
            }

            // Load the reference image if one is specified.
            if (!m_params.m_ref_image_path.empty())
            {
                const string ref_image_path =
                    project.get_search_paths().qualify(m_params.m_ref_image_path);

                RENDERER_LOG_DEBUG("loading reference image %s...", ref_image_path.c_str());

                GenericImageFileReader reader;
                m_ref_image.reset(reader.read(ref_image_path.c_str()));

                m_ref_image_avg_lum = compute_average_luminance(*m_ref_image.get());

                RENDERER_LOG_DEBUG(
                    "reference image average luminance is %s.",
                    pretty_scalar(m_ref_image_avg_lum, 6).c_str());
            }

            print_rendering_thread_count(m_params.m_thread_count);
        }

        virtual ~ProgressiveFrameRenderer()
        {
            // Tell the statistics printing thread to stop.
            m_abort_switch.abort();

            // Wait until the statistics printing thread is terminated.
            m_statistics_thread->join();

            // Delete tile callbacks.
            for (const_each<TileCallbackVector> i = m_tile_callbacks; i; ++i)
                (*i)->release();

            // Delete sample generators.
            for (const_each<SampleGeneratorVector> i = m_sample_generators; i; ++i)
                (*i)->release();
        }

        virtual void release()
        {
            delete this;
        }

        virtual void render()
        {
            start_rendering();
            m_job_queue.wait_until_completion();
        }

        virtual void start_rendering()
        {
            assert(!is_rendering());
            assert(!m_job_queue.has_scheduled_or_running_jobs());

            m_abort_switch.clear();
            m_framebuffer->clear();
            m_sample_counter.clear();

            // Reset sample generators.
            for (size_t i = 0; i < m_sample_generators.size(); ++i)
                m_sample_generators[i]->reset();

            // Schedule the first batch of jobs.
            for (size_t i = 0; i < m_sample_generators.size(); ++i)
            {
                m_job_queue.schedule(
                    new SampleGeneratorJob(
                        m_frame,
                        *m_framebuffer.get(),
                        m_sample_generators[i],
                        m_sample_counter,
                        m_tile_callbacks[i],
                        m_job_queue,
                        i,                              // job index
                        m_sample_generators.size(),     // job count
                        0,                              // pass number
                        m_abort_switch));
            }

            // Start job execution.
            m_job_manager->start();

            // Create and start the statistics printing thread.
            m_statistics_func.reset(
                new StatisticsFunc(
                    m_frame,
                    *m_framebuffer.get(),
                    m_params.m_print_luminance_stats,
                    m_ref_image.get(),
                    m_ref_image_avg_lum,
                    m_abort_switch));
            ThreadFunctionWrapper<StatisticsFunc> wrapper(m_statistics_func.get());
            m_statistics_thread.reset(new thread(wrapper));
        }

        virtual void stop_rendering()
        {
            // Tell rendering jobs and the statistics printing thread to stop.
            m_abort_switch.abort();

            // Stop job execution.
            m_job_manager->stop();

            // Delete all non-executed jobs.
            m_job_queue.clear_scheduled_jobs();

            // Wait until the statistics printing thread is terminated.
            m_statistics_thread->join();
        }

        virtual void terminate_rendering()
        {
            stop_rendering();

            m_statistics_func->write_rms_deviation_file();
        }

        virtual bool is_rendering() const
        {
            return m_job_queue.has_scheduled_or_running_jobs();
        }

      private:
        struct Parameters
        {
            const size_t    m_thread_count;             // number of rendering threads
            const uint64    m_max_sample_count;         // maximum total number of samples to store in the framebuffer
            const bool      m_print_luminance_stats;    // compute and print luminance statistics?
            const string    m_ref_image_path;           // path to the reference image

            // Constructor, extract parameters.
            explicit Parameters(const ParamArray& params)
              : m_thread_count(FrameRendererBase::get_rendering_thread_count(params))
              , m_max_sample_count(params.get_optional<uint64>("max_samples", numeric_limits<uint64>::max()))
              , m_print_luminance_stats(params.get_optional<bool>("print_luminance_statistics", false))
              , m_ref_image_path(params.get_optional<string>("reference_image", ""))
            {
            }
        };

        Frame&                              m_frame;
        const Parameters                    m_params;
        SampleCounter                       m_sample_counter;

        auto_ptr<AccumulationFramebuffer>   m_framebuffer;

        JobQueue                            m_job_queue;
        auto_ptr<JobManager>                m_job_manager;
        AbortSwitch                         m_abort_switch;

        SampleGeneratorVector               m_sample_generators;
        TileCallbackVector                  m_tile_callbacks;

        auto_ptr<Image>                     m_ref_image;
        double                              m_ref_image_avg_lum;

        class StatisticsFunc
          : public NonCopyable
        {
          public:
            StatisticsFunc(
                Frame&                      frame,
                AccumulationFramebuffer&    framebuffer,
                const bool                  print_luminance_stats,
                const Image*                ref_image,
                const double                ref_image_avg_lum,
                AbortSwitch&                abort_switch)
              : m_frame(frame)
              , m_framebuffer(framebuffer)
              , m_print_luminance_stats(print_luminance_stats)
              , m_ref_image(ref_image)
              , m_ref_image_avg_lum(ref_image_avg_lum)
              , m_abort_switch(abort_switch)
              , m_timer_frequency(m_timer.frequency())
              , m_last_time(m_timer.read())
              , m_last_sample_count(0)
            {
            }

            void operator()()
            {
                while (!m_abort_switch.is_aborted())
                {
                    const uint64 time = m_timer.read();
                    const uint64 elapsed_ticks = time - m_last_time;
                    const double elapsed_seconds = static_cast<double>(elapsed_ticks) / m_timer_frequency;

                    if (elapsed_seconds >= 1.0)
                    {
                        print_and_record_statistics(elapsed_seconds);
                        m_last_time = time;
                    }

                    foundation::sleep(5);   // needs full qualification
                }
            }

            void write_rms_deviation_file() const
            {
                if (!m_spp_count_history.empty())
                {
                    MapleFile file("RMS Deviation.mpl");
                    file.define("rmsd", m_spp_count_history, m_rmsd_history);
                    file.plot("rmsd", "RMS Deviation");
                }
            }

          private:
            Frame&                          m_frame;
            AccumulationFramebuffer&        m_framebuffer;
            const bool                      m_print_luminance_stats;
            const Image*                    m_ref_image;
            const double                    m_ref_image_avg_lum;
            AbortSwitch&                    m_abort_switch;

            DefaultWallclockTimer           m_timer;
            uint64                          m_timer_frequency;
            uint64                          m_last_time;

            uint64                          m_last_sample_count;
            FixedSizeHistory<double, 16>    m_sps_count_history;    // samples per second history
            vector<double>                  m_spp_count_history;    // samples per pixel history
            vector<double>                  m_rmsd_history;         // RMS deviation history

            void print_and_record_statistics(const double elapsed_seconds)
            {
                print_performance_statistics(elapsed_seconds);

                if (m_print_luminance_stats || m_ref_image)
                    print_and_record_convergence_statistics();
            }

            void print_performance_statistics(const double elapsed_seconds)
            {
                const uint64 new_sample_count = m_framebuffer.get_sample_count();
                const uint64 pixel_count = static_cast<uint64>(m_frame.image().properties().m_pixel_count);
                const double spp_count = static_cast<double>(new_sample_count) / pixel_count;
                const double sps_count = static_cast<double>(new_sample_count - m_last_sample_count) / elapsed_seconds;

                m_sps_count_history.insert(sps_count);

                const uint64 avg_sps_count = truncate<uint64>(m_sps_count_history.compute_average());

                RENDERER_LOG_INFO(
                    "%s samples, %s samples/pixel, %s samples/second",
                    pretty_uint(new_sample_count).c_str(),
                    pretty_scalar(spp_count).c_str(),
                    pretty_uint(avg_sps_count).c_str());

                m_last_sample_count = new_sample_count;
            }

            void print_and_record_convergence_statistics()
            {
                assert(m_print_luminance_stats || m_ref_image);

                string output;

                Image current_image(m_frame.image());
                m_frame.transform_to_output_color_space(current_image);

                if (m_print_luminance_stats)
                {
                    const double avg_lum = compute_average_luminance(current_image);
                    output += "average luminance " + pretty_scalar(avg_lum, 6);

                    if (m_ref_image)
                    {
                        const double avg_lum_delta = abs(m_ref_image_avg_lum - avg_lum);
                        output += " (";
                        output += pretty_percent(avg_lum_delta, m_ref_image_avg_lum, 3);
                        output += " error)";
                    }
                }

                if (m_ref_image)
                {
                    if (m_print_luminance_stats)
                        output += ", ";

                    const double spp_count =
                          static_cast<double>(m_framebuffer.get_sample_count())
                        / m_frame.image().properties().m_pixel_count;

                    const double rmsd = compute_rms_deviation(current_image, *m_ref_image);

                    output += "rms deviation " + pretty_scalar(rmsd, 6);

                    m_spp_count_history.push_back(spp_count);
                    m_rmsd_history.push_back(rmsd);
                }

                RENDERER_LOG_DEBUG("%s", output.c_str());
            }
        };

        auto_ptr<StatisticsFunc>            m_statistics_func;
        auto_ptr<thread>                    m_statistics_thread;
    };
}

//
// ProgressiveFrameRendererFactory class implementation.
//

ProgressiveFrameRendererFactory::ProgressiveFrameRendererFactory(
    const Project&              project,
    ISampleGeneratorFactory*    generator_factory,
    ITileCallbackFactory*       callback_factory,
    const ParamArray&           params)
  : m_project(project)
  , m_generator_factory(generator_factory)
  , m_callback_factory(callback_factory)
  , m_params(params)
{
}

void ProgressiveFrameRendererFactory::release()
{
    delete this;
}

IFrameRenderer* ProgressiveFrameRendererFactory::create()
{
    return
        new ProgressiveFrameRenderer(
            m_project,
            m_generator_factory,
            m_callback_factory,
            m_params);
}

IFrameRenderer* ProgressiveFrameRendererFactory::create(
    const Project&              project,
    ISampleGeneratorFactory*    generator_factory,
    ITileCallbackFactory*       callback_factory,
    const ParamArray&           params)
{
    return
        new ProgressiveFrameRenderer(
            project,
            generator_factory,
            callback_factory,
            params);
}

}   // namespace renderer
<|endoftext|>


<commit_before>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

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

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

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

#include "tensorflow/core/platform/hadoop/hadoop_file_system.h"

#include <errno.h>

#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/io/path.h"
#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/file_system.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/posix/error.h"
#include "third_party/hadoop/hdfs.h"

namespace tensorflow {

template <typename R, typename... Args>
Status BindFunc(void* handle, const char* name,
                std::function<R(Args...)>* func) {
  void* symbol_ptr = nullptr;
  TF_RETURN_IF_ERROR(
      Env::Default()->GetSymbolFromLibrary(handle, name, &symbol_ptr));
  *func = reinterpret_cast<R (*)(Args...)>(symbol_ptr);
  return Status::OK();
}

class LibHDFS {
 public:
  static LibHDFS* Load() {
    static LibHDFS* lib = []() -> LibHDFS* {
      LibHDFS* lib = new LibHDFS;
      lib->LoadAndBind();
      return lib;
    }();

    return lib;
  }

  // The status, if any, from failure to load.
  Status status() { return status_; }

  std::function<hdfsFS(hdfsBuilder*)> hdfsBuilderConnect;
  std::function<hdfsBuilder*()> hdfsNewBuilder;
  std::function<void(hdfsBuilder*, const char*)> hdfsBuilderSetNameNode;
  std::function<int(hdfsFS, hdfsFile)> hdfsCloseFile;
  std::function<tSize(hdfsFS, hdfsFile, tOffset, void*, tSize)> hdfsPread;
  std::function<tSize(hdfsFS, hdfsFile, const void*, tSize)> hdfsWrite;
  std::function<int(hdfsFS, hdfsFile)> hdfsFlush;
  std::function<int(hdfsFS, hdfsFile)> hdfsHSync;
  std::function<hdfsFile(hdfsFS, const char*, int, int, short, tSize)>
      hdfsOpenFile;
  std::function<int(hdfsFS, const char*)> hdfsExists;
  std::function<hdfsFileInfo*(hdfsFS, const char*, int*)> hdfsListDirectory;
  std::function<void(hdfsFileInfo*, int)> hdfsFreeFileInfo;
  std::function<int(hdfsFS, const char*, int recursive)> hdfsDelete;
  std::function<int(hdfsFS, const char*)> hdfsCreateDirectory;
  std::function<hdfsFileInfo*(hdfsFS, const char*)> hdfsGetPathInfo;
  std::function<int(hdfsFS, const char*, const char*)> hdfsRename;

 private:
  void LoadAndBind() {
    auto TryLoadAndBind = [this](const char* name, void** handle) -> Status {
      TF_RETURN_IF_ERROR(Env::Default()->LoadLibrary(name, handle));
#define BIND_HDFS_FUNC(function) \
  TF_RETURN_IF_ERROR(BindFunc(*handle, #function, &function));

      BIND_HDFS_FUNC(hdfsBuilderConnect);
      BIND_HDFS_FUNC(hdfsNewBuilder);
      BIND_HDFS_FUNC(hdfsBuilderSetNameNode);
      BIND_HDFS_FUNC(hdfsCloseFile);
      BIND_HDFS_FUNC(hdfsPread);
      BIND_HDFS_FUNC(hdfsWrite);
      BIND_HDFS_FUNC(hdfsFlush);
      BIND_HDFS_FUNC(hdfsHSync);
      BIND_HDFS_FUNC(hdfsOpenFile);
      BIND_HDFS_FUNC(hdfsExists);
      BIND_HDFS_FUNC(hdfsListDirectory);
      BIND_HDFS_FUNC(hdfsFreeFileInfo);
      BIND_HDFS_FUNC(hdfsDelete);
      BIND_HDFS_FUNC(hdfsCreateDirectory);
      BIND_HDFS_FUNC(hdfsGetPathInfo);
      BIND_HDFS_FUNC(hdfsRename);
#undef BIND_HDFS_FUNC
      return Status::OK();
    };

    // libhdfs.so won't be in the standard locations. Use the path as specified
    // in the libhdfs documentation.
    char* hdfs_home = getenv("HADOOP_HDFS_HOME");
    if (hdfs_home == nullptr) {
      status_ = errors::FailedPrecondition(
          "Environment variable HADOOP_HDFS_HOME not set");
      return;
    }
    string path = io::JoinPath(hdfs_home, "lib", "native", "libhdfs.so");
    status_ = TryLoadAndBind(path.c_str(), &handle_);
    return;
  }

  Status status_;
  void* handle_ = nullptr;
};

HadoopFileSystem::HadoopFileSystem() : hdfs_(LibHDFS::Load()) {}

HadoopFileSystem::~HadoopFileSystem() {}

// We rely on HDFS connection caching here. The HDFS client calls
// org.apache.hadoop.fs.FileSystem.get(), which caches the connection
// internally.
Status HadoopFileSystem::Connect(StringPiece fname, hdfsFS* fs) {
  TF_RETURN_IF_ERROR(hdfs_->status());

  StringPiece scheme, namenode, path;
  ParseURI(fname, &scheme, &namenode, &path);

  hdfsBuilder* builder = hdfs_->hdfsNewBuilder();
  if (scheme == "file") {
    hdfs_->hdfsBuilderSetNameNode(builder, nullptr);
  } else {
    hdfs_->hdfsBuilderSetNameNode(builder, namenode.ToString().c_str());
  }
  *fs = hdfs_->hdfsBuilderConnect(builder);
  if (*fs == nullptr) {
    return errors::NotFound(strerror(errno));
  }
  return Status::OK();
}

string HadoopFileSystem::TranslateName(const string& name) const {
  StringPiece scheme, namenode, path;
  ParseURI(name, &scheme, &namenode, &path);
  return path.ToString();
}

class HDFSRandomAccessFile : public RandomAccessFile {
 public:
  HDFSRandomAccessFile(const string& fname, LibHDFS* hdfs, hdfsFS fs,
                       hdfsFile file)
      : filename_(fname), hdfs_(hdfs), fs_(fs), file_(file) {}

  ~HDFSRandomAccessFile() override { hdfs_->hdfsCloseFile(fs_, file_); }

  Status Read(uint64 offset, size_t n, StringPiece* result,
              char* scratch) const override {
    Status s;
    char* dst = scratch;
    while (n > 0 && s.ok()) {
      tSize r = hdfs_->hdfsPread(fs_, file_, static_cast<tOffset>(offset), dst,
                                 static_cast<tSize>(n));
      if (r > 0) {
        dst += r;
        n -= r;
        offset += r;
      } else if (r == 0) {
        s = Status(error::OUT_OF_RANGE, "Read less bytes than requested");
      } else if (errno == EINTR || errno == EAGAIN) {
        // hdfsPread may return EINTR too. Just retry.
      } else {
        s = IOError(filename_, errno);
      }
    }
    *result = StringPiece(scratch, dst - scratch);
    return s;
  }

 private:
  string filename_;
  LibHDFS* hdfs_;
  hdfsFS fs_;
  hdfsFile file_;
};

Status HadoopFileSystem::NewRandomAccessFile(
    const string& fname, std::unique_ptr<RandomAccessFile>* result) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(fname, &fs));

  hdfsFile file =
      hdfs_->hdfsOpenFile(fs, TranslateName(fname).c_str(), O_RDONLY, 0, 0, 0);
  if (file == nullptr) {
    return IOError(fname, errno);
  }
  result->reset(new HDFSRandomAccessFile(fname, hdfs_, fs, file));
  return Status::OK();
}

class HDFSWritableFile : public WritableFile {
 public:
  HDFSWritableFile(const string& fname, LibHDFS* hdfs, hdfsFS fs, hdfsFile file)
      : filename_(fname), hdfs_(hdfs), fs_(fs), file_(file) {}

  ~HDFSWritableFile() override {
    if (file_ != nullptr) {
      Close();
    }
  }

  Status Append(const StringPiece& data) override {
    if (hdfs_->hdfsWrite(fs_, file_, data.data(),
                         static_cast<tSize>(data.size())) == -1) {
      return IOError(filename_, errno);
    }
    return Status::OK();
  }

  Status Close() override {
    Status result;
    if (hdfs_->hdfsCloseFile(fs_, file_) != 0) {
      result = IOError(filename_, errno);
    }
    hdfs_ = nullptr;
    fs_ = nullptr;
    file_ = nullptr;
    return result;
  }

  Status Flush() override {
    if (hdfs_->hdfsFlush(fs_, file_) != 0) {
      return IOError(filename_, errno);
    }
    return Status::OK();
  }

  Status Sync() override {
    if (hdfs_->hdfsHSync(fs_, file_) != 0) {
      return IOError(filename_, errno);
    }
    return Status::OK();
  }

 private:
  string filename_;
  LibHDFS* hdfs_;
  hdfsFS fs_;
  hdfsFile file_;
};

Status HadoopFileSystem::NewWritableFile(
    const string& fname, std::unique_ptr<WritableFile>* result) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(fname, &fs));

  hdfsFile file =
      hdfs_->hdfsOpenFile(fs, TranslateName(fname).c_str(), O_WRONLY, 0, 0, 0);
  if (file == nullptr) {
    return IOError(fname, errno);
  }
  result->reset(new HDFSWritableFile(fname, hdfs_, fs, file));
  return Status::OK();
}

Status HadoopFileSystem::NewAppendableFile(
    const string& fname, std::unique_ptr<WritableFile>* result) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(fname, &fs));

  hdfsFile file = hdfs_->hdfsOpenFile(fs, TranslateName(fname).c_str(),
                                      O_WRONLY | O_APPEND, 0, 0, 0);
  if (file == nullptr) {
    return IOError(fname, errno);
  }
  result->reset(new HDFSWritableFile(fname, hdfs_, fs, file));
  return Status::OK();
}

Status HadoopFileSystem::NewReadOnlyMemoryRegionFromFile(
    const string& fname, std::unique_ptr<ReadOnlyMemoryRegion>* result) {
  // hadoopReadZero() technically supports this call with the following
  // caveats:
  // - It only works up to 2 GB. We'd have to Stat() the file to ensure that
  //   it fits.
  // - If not on the local filesystem, the entire file will be read, making
  //   it inefficient for callers that assume typical mmap() behavior.
  return errors::Unimplemented("HDFS does not support ReadOnlyMemoryRegion");
}

bool HadoopFileSystem::FileExists(const string& fname) {
  hdfsFS fs = nullptr;
  Status status = Connect(fname, &fs);
  if (!status.ok()) {
    LOG(ERROR) << "Connect failed: " << status.error_message();
    return false;
  }

  return hdfs_->hdfsExists(fs, TranslateName(fname).c_str()) == 0;
}

Status HadoopFileSystem::GetChildren(const string& dir,
                                     std::vector<string>* result) {
  result->clear();
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(dir, &fs));

  // hdfsListDirectory returns nullptr if the directory is empty. Do a separate
  // check to verify the directory exists first.
  FileStatistics stat;
  TF_RETURN_IF_ERROR(Stat(dir, &stat));

  int entries = 0;
  hdfsFileInfo* info =
      hdfs_->hdfsListDirectory(fs, TranslateName(dir).c_str(), &entries);
  if (info == nullptr) {
    if (stat.is_directory) {
      // Assume it's an empty directory.
      return Status::OK();
    }
    return IOError(dir, errno);
  }
  for (int i = 0; i < entries; i++) {
    result->push_back(io::Basename(info[i].mName).ToString());
  }
  hdfs_->hdfsFreeFileInfo(info, entries);
  return Status::OK();
}

Status HadoopFileSystem::DeleteFile(const string& fname) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(fname, &fs));

  if (hdfs_->hdfsDelete(fs, TranslateName(fname).c_str(),
                        /*recursive=*/0) != 0) {
    return IOError(fname, errno);
  }
  return Status::OK();
}

Status HadoopFileSystem::CreateDir(const string& dir) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(dir, &fs));

  if (hdfs_->hdfsCreateDirectory(fs, TranslateName(dir).c_str()) != 0) {
    return IOError(dir, errno);
  }
  return Status::OK();
}

Status HadoopFileSystem::DeleteDir(const string& dir) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(dir, &fs));

  // Count the number of entries in the directory, and only delete if it's
  // non-empty. This is consistent with the interface, but note that there's
  // a race condition where a file may be added after this check, in which
  // case the directory will still be deleted.
  int entries = 0;
  hdfsFileInfo* info =
      hdfs_->hdfsListDirectory(fs, TranslateName(dir).c_str(), &entries);
  if (info != nullptr) {
    return IOError(dir, errno);
  }
  hdfs_->hdfsFreeFileInfo(info, entries);

  if (entries > 0) {
    return errors::FailedPrecondition("Cannot delete a non-empty directory.");
  }
  if (hdfs_->hdfsDelete(fs, TranslateName(dir).c_str(),
                        /*recursive=*/1) != 0) {
    return IOError(dir, errno);
  }
  return Status::OK();
}

Status HadoopFileSystem::GetFileSize(const string& fname, uint64* size) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(fname, &fs));

  hdfsFileInfo* info = hdfs_->hdfsGetPathInfo(fs, TranslateName(fname).c_str());
  if (info == nullptr) {
    return IOError(fname, errno);
  }
  *size = static_cast<uint64>(info->mSize);
  hdfs_->hdfsFreeFileInfo(info, 1);
  return Status::OK();
}

Status HadoopFileSystem::RenameFile(const string& src, const string& target) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(src, &fs));

  if (hdfs_->hdfsRename(fs, TranslateName(src).c_str(),
                        TranslateName(target).c_str()) != 0) {
    return IOError(src, errno);
  }
  return Status::OK();
}

Status HadoopFileSystem::Stat(const string& fname, FileStatistics* stats) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(fname, &fs));

  hdfsFileInfo* info = hdfs_->hdfsGetPathInfo(fs, TranslateName(fname).c_str());
  if (info == nullptr) {
    return IOError(fname, errno);
  }
  stats->length = static_cast<int64>(info->mSize);
  stats->mtime_nsec = static_cast<int64>(info->mLastMod) * 1e9;
  stats->is_directory = info->mKind == kObjectKindDirectory;
  hdfs_->hdfsFreeFileInfo(info, 1);
  return Status::OK();
}

REGISTER_FILE_SYSTEM("hdfs", HadoopFileSystem);

}  // namespace tensorflow
<commit_msg>Fix usage of a temporary when passing the namenode as a c_str(). Change: 134095364<commit_after>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

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

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

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

#include "tensorflow/core/platform/hadoop/hadoop_file_system.h"

#include <errno.h>

#include "tensorflow/core/lib/core/status.h"
#include "tensorflow/core/lib/io/path.h"
#include "tensorflow/core/lib/strings/strcat.h"
#include "tensorflow/core/platform/env.h"
#include "tensorflow/core/platform/file_system.h"
#include "tensorflow/core/platform/logging.h"
#include "tensorflow/core/platform/posix/error.h"
#include "third_party/hadoop/hdfs.h"

namespace tensorflow {

template <typename R, typename... Args>
Status BindFunc(void* handle, const char* name,
                std::function<R(Args...)>* func) {
  void* symbol_ptr = nullptr;
  TF_RETURN_IF_ERROR(
      Env::Default()->GetSymbolFromLibrary(handle, name, &symbol_ptr));
  *func = reinterpret_cast<R (*)(Args...)>(symbol_ptr);
  return Status::OK();
}

class LibHDFS {
 public:
  static LibHDFS* Load() {
    static LibHDFS* lib = []() -> LibHDFS* {
      LibHDFS* lib = new LibHDFS;
      lib->LoadAndBind();
      return lib;
    }();

    return lib;
  }

  // The status, if any, from failure to load.
  Status status() { return status_; }

  std::function<hdfsFS(hdfsBuilder*)> hdfsBuilderConnect;
  std::function<hdfsBuilder*()> hdfsNewBuilder;
  std::function<void(hdfsBuilder*, const char*)> hdfsBuilderSetNameNode;
  std::function<int(hdfsFS, hdfsFile)> hdfsCloseFile;
  std::function<tSize(hdfsFS, hdfsFile, tOffset, void*, tSize)> hdfsPread;
  std::function<tSize(hdfsFS, hdfsFile, const void*, tSize)> hdfsWrite;
  std::function<int(hdfsFS, hdfsFile)> hdfsFlush;
  std::function<int(hdfsFS, hdfsFile)> hdfsHSync;
  std::function<hdfsFile(hdfsFS, const char*, int, int, short, tSize)>
      hdfsOpenFile;
  std::function<int(hdfsFS, const char*)> hdfsExists;
  std::function<hdfsFileInfo*(hdfsFS, const char*, int*)> hdfsListDirectory;
  std::function<void(hdfsFileInfo*, int)> hdfsFreeFileInfo;
  std::function<int(hdfsFS, const char*, int recursive)> hdfsDelete;
  std::function<int(hdfsFS, const char*)> hdfsCreateDirectory;
  std::function<hdfsFileInfo*(hdfsFS, const char*)> hdfsGetPathInfo;
  std::function<int(hdfsFS, const char*, const char*)> hdfsRename;

 private:
  void LoadAndBind() {
    auto TryLoadAndBind = [this](const char* name, void** handle) -> Status {
      TF_RETURN_IF_ERROR(Env::Default()->LoadLibrary(name, handle));
#define BIND_HDFS_FUNC(function) \
  TF_RETURN_IF_ERROR(BindFunc(*handle, #function, &function));

      BIND_HDFS_FUNC(hdfsBuilderConnect);
      BIND_HDFS_FUNC(hdfsNewBuilder);
      BIND_HDFS_FUNC(hdfsBuilderSetNameNode);
      BIND_HDFS_FUNC(hdfsCloseFile);
      BIND_HDFS_FUNC(hdfsPread);
      BIND_HDFS_FUNC(hdfsWrite);
      BIND_HDFS_FUNC(hdfsFlush);
      BIND_HDFS_FUNC(hdfsHSync);
      BIND_HDFS_FUNC(hdfsOpenFile);
      BIND_HDFS_FUNC(hdfsExists);
      BIND_HDFS_FUNC(hdfsListDirectory);
      BIND_HDFS_FUNC(hdfsFreeFileInfo);
      BIND_HDFS_FUNC(hdfsDelete);
      BIND_HDFS_FUNC(hdfsCreateDirectory);
      BIND_HDFS_FUNC(hdfsGetPathInfo);
      BIND_HDFS_FUNC(hdfsRename);
#undef BIND_HDFS_FUNC
      return Status::OK();
    };

    // libhdfs.so won't be in the standard locations. Use the path as specified
    // in the libhdfs documentation.
    char* hdfs_home = getenv("HADOOP_HDFS_HOME");
    if (hdfs_home == nullptr) {
      status_ = errors::FailedPrecondition(
          "Environment variable HADOOP_HDFS_HOME not set");
      return;
    }
    string path = io::JoinPath(hdfs_home, "lib", "native", "libhdfs.so");
    status_ = TryLoadAndBind(path.c_str(), &handle_);
    return;
  }

  Status status_;
  void* handle_ = nullptr;
};

HadoopFileSystem::HadoopFileSystem() : hdfs_(LibHDFS::Load()) {}

HadoopFileSystem::~HadoopFileSystem() {}

// We rely on HDFS connection caching here. The HDFS client calls
// org.apache.hadoop.fs.FileSystem.get(), which caches the connection
// internally.
Status HadoopFileSystem::Connect(StringPiece fname, hdfsFS* fs) {
  TF_RETURN_IF_ERROR(hdfs_->status());

  StringPiece scheme, namenode, path;
  ParseURI(fname, &scheme, &namenode, &path);
  const string nn = namenode.ToString();

  hdfsBuilder* builder = hdfs_->hdfsNewBuilder();
  if (scheme == "file") {
    hdfs_->hdfsBuilderSetNameNode(builder, nullptr);
  } else {
    hdfs_->hdfsBuilderSetNameNode(builder, nn.c_str());
  }
  *fs = hdfs_->hdfsBuilderConnect(builder);
  if (*fs == nullptr) {
    return errors::NotFound(strerror(errno));
  }
  return Status::OK();
}

string HadoopFileSystem::TranslateName(const string& name) const {
  StringPiece scheme, namenode, path;
  ParseURI(name, &scheme, &namenode, &path);
  return path.ToString();
}

class HDFSRandomAccessFile : public RandomAccessFile {
 public:
  HDFSRandomAccessFile(const string& fname, LibHDFS* hdfs, hdfsFS fs,
                       hdfsFile file)
      : filename_(fname), hdfs_(hdfs), fs_(fs), file_(file) {}

  ~HDFSRandomAccessFile() override { hdfs_->hdfsCloseFile(fs_, file_); }

  Status Read(uint64 offset, size_t n, StringPiece* result,
              char* scratch) const override {
    Status s;
    char* dst = scratch;
    while (n > 0 && s.ok()) {
      tSize r = hdfs_->hdfsPread(fs_, file_, static_cast<tOffset>(offset), dst,
                                 static_cast<tSize>(n));
      if (r > 0) {
        dst += r;
        n -= r;
        offset += r;
      } else if (r == 0) {
        s = Status(error::OUT_OF_RANGE, "Read less bytes than requested");
      } else if (errno == EINTR || errno == EAGAIN) {
        // hdfsPread may return EINTR too. Just retry.
      } else {
        s = IOError(filename_, errno);
      }
    }
    *result = StringPiece(scratch, dst - scratch);
    return s;
  }

 private:
  string filename_;
  LibHDFS* hdfs_;
  hdfsFS fs_;
  hdfsFile file_;
};

Status HadoopFileSystem::NewRandomAccessFile(
    const string& fname, std::unique_ptr<RandomAccessFile>* result) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(fname, &fs));

  hdfsFile file =
      hdfs_->hdfsOpenFile(fs, TranslateName(fname).c_str(), O_RDONLY, 0, 0, 0);
  if (file == nullptr) {
    return IOError(fname, errno);
  }
  result->reset(new HDFSRandomAccessFile(fname, hdfs_, fs, file));
  return Status::OK();
}

class HDFSWritableFile : public WritableFile {
 public:
  HDFSWritableFile(const string& fname, LibHDFS* hdfs, hdfsFS fs, hdfsFile file)
      : filename_(fname), hdfs_(hdfs), fs_(fs), file_(file) {}

  ~HDFSWritableFile() override {
    if (file_ != nullptr) {
      Close();
    }
  }

  Status Append(const StringPiece& data) override {
    if (hdfs_->hdfsWrite(fs_, file_, data.data(),
                         static_cast<tSize>(data.size())) == -1) {
      return IOError(filename_, errno);
    }
    return Status::OK();
  }

  Status Close() override {
    Status result;
    if (hdfs_->hdfsCloseFile(fs_, file_) != 0) {
      result = IOError(filename_, errno);
    }
    hdfs_ = nullptr;
    fs_ = nullptr;
    file_ = nullptr;
    return result;
  }

  Status Flush() override {
    if (hdfs_->hdfsFlush(fs_, file_) != 0) {
      return IOError(filename_, errno);
    }
    return Status::OK();
  }

  Status Sync() override {
    if (hdfs_->hdfsHSync(fs_, file_) != 0) {
      return IOError(filename_, errno);
    }
    return Status::OK();
  }

 private:
  string filename_;
  LibHDFS* hdfs_;
  hdfsFS fs_;
  hdfsFile file_;
};

Status HadoopFileSystem::NewWritableFile(
    const string& fname, std::unique_ptr<WritableFile>* result) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(fname, &fs));

  hdfsFile file =
      hdfs_->hdfsOpenFile(fs, TranslateName(fname).c_str(), O_WRONLY, 0, 0, 0);
  if (file == nullptr) {
    return IOError(fname, errno);
  }
  result->reset(new HDFSWritableFile(fname, hdfs_, fs, file));
  return Status::OK();
}

Status HadoopFileSystem::NewAppendableFile(
    const string& fname, std::unique_ptr<WritableFile>* result) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(fname, &fs));

  hdfsFile file = hdfs_->hdfsOpenFile(fs, TranslateName(fname).c_str(),
                                      O_WRONLY | O_APPEND, 0, 0, 0);
  if (file == nullptr) {
    return IOError(fname, errno);
  }
  result->reset(new HDFSWritableFile(fname, hdfs_, fs, file));
  return Status::OK();
}

Status HadoopFileSystem::NewReadOnlyMemoryRegionFromFile(
    const string& fname, std::unique_ptr<ReadOnlyMemoryRegion>* result) {
  // hadoopReadZero() technically supports this call with the following
  // caveats:
  // - It only works up to 2 GB. We'd have to Stat() the file to ensure that
  //   it fits.
  // - If not on the local filesystem, the entire file will be read, making
  //   it inefficient for callers that assume typical mmap() behavior.
  return errors::Unimplemented("HDFS does not support ReadOnlyMemoryRegion");
}

bool HadoopFileSystem::FileExists(const string& fname) {
  hdfsFS fs = nullptr;
  Status status = Connect(fname, &fs);
  if (!status.ok()) {
    LOG(ERROR) << "Connect failed: " << status.error_message();
    return false;
  }

  return hdfs_->hdfsExists(fs, TranslateName(fname).c_str()) == 0;
}

Status HadoopFileSystem::GetChildren(const string& dir,
                                     std::vector<string>* result) {
  result->clear();
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(dir, &fs));

  // hdfsListDirectory returns nullptr if the directory is empty. Do a separate
  // check to verify the directory exists first.
  FileStatistics stat;
  TF_RETURN_IF_ERROR(Stat(dir, &stat));

  int entries = 0;
  hdfsFileInfo* info =
      hdfs_->hdfsListDirectory(fs, TranslateName(dir).c_str(), &entries);
  if (info == nullptr) {
    if (stat.is_directory) {
      // Assume it's an empty directory.
      return Status::OK();
    }
    return IOError(dir, errno);
  }
  for (int i = 0; i < entries; i++) {
    result->push_back(io::Basename(info[i].mName).ToString());
  }
  hdfs_->hdfsFreeFileInfo(info, entries);
  return Status::OK();
}

Status HadoopFileSystem::DeleteFile(const string& fname) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(fname, &fs));

  if (hdfs_->hdfsDelete(fs, TranslateName(fname).c_str(),
                        /*recursive=*/0) != 0) {
    return IOError(fname, errno);
  }
  return Status::OK();
}

Status HadoopFileSystem::CreateDir(const string& dir) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(dir, &fs));

  if (hdfs_->hdfsCreateDirectory(fs, TranslateName(dir).c_str()) != 0) {
    return IOError(dir, errno);
  }
  return Status::OK();
}

Status HadoopFileSystem::DeleteDir(const string& dir) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(dir, &fs));

  // Count the number of entries in the directory, and only delete if it's
  // non-empty. This is consistent with the interface, but note that there's
  // a race condition where a file may be added after this check, in which
  // case the directory will still be deleted.
  int entries = 0;
  hdfsFileInfo* info =
      hdfs_->hdfsListDirectory(fs, TranslateName(dir).c_str(), &entries);
  if (info != nullptr) {
    return IOError(dir, errno);
  }
  hdfs_->hdfsFreeFileInfo(info, entries);

  if (entries > 0) {
    return errors::FailedPrecondition("Cannot delete a non-empty directory.");
  }
  if (hdfs_->hdfsDelete(fs, TranslateName(dir).c_str(),
                        /*recursive=*/1) != 0) {
    return IOError(dir, errno);
  }
  return Status::OK();
}

Status HadoopFileSystem::GetFileSize(const string& fname, uint64* size) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(fname, &fs));

  hdfsFileInfo* info = hdfs_->hdfsGetPathInfo(fs, TranslateName(fname).c_str());
  if (info == nullptr) {
    return IOError(fname, errno);
  }
  *size = static_cast<uint64>(info->mSize);
  hdfs_->hdfsFreeFileInfo(info, 1);
  return Status::OK();
}

Status HadoopFileSystem::RenameFile(const string& src, const string& target) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(src, &fs));

  if (hdfs_->hdfsRename(fs, TranslateName(src).c_str(),
                        TranslateName(target).c_str()) != 0) {
    return IOError(src, errno);
  }
  return Status::OK();
}

Status HadoopFileSystem::Stat(const string& fname, FileStatistics* stats) {
  hdfsFS fs = nullptr;
  TF_RETURN_IF_ERROR(Connect(fname, &fs));

  hdfsFileInfo* info = hdfs_->hdfsGetPathInfo(fs, TranslateName(fname).c_str());
  if (info == nullptr) {
    return IOError(fname, errno);
  }
  stats->length = static_cast<int64>(info->mSize);
  stats->mtime_nsec = static_cast<int64>(info->mLastMod) * 1e9;
  stats->is_directory = info->mKind == kObjectKindDirectory;
  hdfs_->hdfsFreeFileInfo(info, 1);
  return Status::OK();
}

REGISTER_FILE_SYSTEM("hdfs", HadoopFileSystem);

}  // namespace tensorflow
<|endoftext|>


<commit_before>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

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

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

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

#include <cstdint>
#include <cstdlib>

#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/micro/benchmarks/keyword_scrambled_model_data.h"
#include "tensorflow/lite/micro/benchmarks/micro_benchmark.h"
#include "tensorflow/lite/micro/kernels/fully_connected.h"
#include "tensorflow/lite/micro/kernels/softmax.h"
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/micro/micro_profiler.h"
#include "tensorflow/lite/micro/system_setup.h"

/*
 * Keyword Spotting Benchmark for performance optimizations. The model used in
 * this benchmark only serves as a reference. The values assigned to the model
 * weights and parameters are not representative of the original model.
 */

namespace tflite {

using KeywordBenchmarkRunner = MicroBenchmarkRunner<int16_t>;
using KeywordOpResolver = MicroMutableOpResolver<6>;

#if defined(HEXAGON)
// TODO(b/174781826): reduce arena usage for optimized Hexagon kernels.
constexpr int kOptimizedKernelArenaIncrement = 21000;
#else
constexpr int kOptimizedKernelArenaIncrement = 0;
#endif

// Create an area of memory to use for input, output, and intermediate arrays.
// Align arena to 16 bytes to avoid alignment warnings on certain platforms.
constexpr int kTensorArenaSize = 21 * 1024 + kOptimizedKernelArenaIncrement;
alignas(16) uint8_t tensor_arena[kTensorArenaSize];

uint8_t benchmark_runner_buffer[sizeof(KeywordBenchmarkRunner)];
uint8_t op_resolver_buffer[sizeof(KeywordOpResolver)];

// Initialize benchmark runner instance explicitly to avoid global init order
// issues on Sparkfun. Use new since static variables within a method
// are automatically surrounded by locking, which breaks bluepill and stm32f4.
KeywordBenchmarkRunner* CreateBenchmarkRunner(MicroProfiler* profiler) {
  // We allocate the KeywordOpResolver from a global buffer because the object's
  // lifetime must exceed that of the KeywordBenchmarkRunner object.
  KeywordOpResolver* op_resolver = new (op_resolver_buffer) KeywordOpResolver();
  op_resolver->AddFullyConnected(tflite::Register_FULLY_CONNECTED_INT8());
  op_resolver->AddQuantize();
  op_resolver->AddSoftmax(tflite::Register_SOFTMAX_INT8_INT16());
  op_resolver->AddSvdf();

  return new (benchmark_runner_buffer)
      KeywordBenchmarkRunner(g_keyword_scrambled_model_data, op_resolver,
                             tensor_arena, kTensorArenaSize, profiler);
}

void KeywordRunNIerations(int iterations, const char* tag,
                          KeywordBenchmarkRunner& benchmark_runner,
                          MicroProfiler& profiler) {
  int32_t ticks = 0;
  for (int i = 0; i < iterations; ++i) {
    benchmark_runner.SetRandomInput(i);
    profiler.ClearEvents();
    benchmark_runner.RunSingleIteration();
    ticks += profiler.GetTotalTicks();
  }
  MicroPrintf("%s took %d ticks (%d ms)", tag, ticks, TicksToMs(ticks));
}

}  // namespace tflite

int main(int argc, char** argv) {
  tflite::InitializeTarget();
  tflite::MicroProfiler profiler;

  uint32_t event_handle = profiler.BeginEvent("InitializeKeywordRunner");
  tflite::KeywordBenchmarkRunner* benchmark_runner =
      CreateBenchmarkRunner(&profiler);
  profiler.EndEvent(event_handle);
  profiler.Log();
  MicroPrintf("");  // null MicroPrintf serves as a newline.

  tflite::KeywordRunNIerations(1, "KeywordRunNIerations(1)", *benchmark_runner,
                               profiler);
  profiler.Log();
  MicroPrintf("");  // null MicroPrintf serves as a newline.

  tflite::KeywordRunNIerations(10, "KeywordRunNIerations(10)",
                               *benchmark_runner, profiler);
  MicroPrintf("");  // null MicroPrintf serves as a newline.

  benchmark_runner->PrintAllocations();
}
<commit_msg>Updated QC implementation no longer needs additional arena for keyword_benchmark. (#221)<commit_after>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

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

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

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

#include <cstdint>
#include <cstdlib>

#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/micro/benchmarks/keyword_scrambled_model_data.h"
#include "tensorflow/lite/micro/benchmarks/micro_benchmark.h"
#include "tensorflow/lite/micro/kernels/fully_connected.h"
#include "tensorflow/lite/micro/kernels/softmax.h"
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/micro/micro_profiler.h"
#include "tensorflow/lite/micro/system_setup.h"

/*
 * Keyword Spotting Benchmark for performance optimizations. The model used in
 * this benchmark only serves as a reference. The values assigned to the model
 * weights and parameters are not representative of the original model.
 */

namespace tflite {

using KeywordBenchmarkRunner = MicroBenchmarkRunner<int16_t>;
using KeywordOpResolver = MicroMutableOpResolver<6>;

// Create an area of memory to use for input, output, and intermediate arrays.
// Align arena to 16 bytes to avoid alignment warnings on certain platforms.
constexpr int kTensorArenaSize = 21 * 1024;
alignas(16) uint8_t tensor_arena[kTensorArenaSize];

uint8_t benchmark_runner_buffer[sizeof(KeywordBenchmarkRunner)];
uint8_t op_resolver_buffer[sizeof(KeywordOpResolver)];

// Initialize benchmark runner instance explicitly to avoid global init order
// issues on Sparkfun. Use new since static variables within a method
// are automatically surrounded by locking, which breaks bluepill and stm32f4.
KeywordBenchmarkRunner* CreateBenchmarkRunner(MicroProfiler* profiler) {
  // We allocate the KeywordOpResolver from a global buffer because the object's
  // lifetime must exceed that of the KeywordBenchmarkRunner object.
  KeywordOpResolver* op_resolver = new (op_resolver_buffer) KeywordOpResolver();
  op_resolver->AddFullyConnected(tflite::Register_FULLY_CONNECTED_INT8());
  op_resolver->AddQuantize();
  op_resolver->AddSoftmax(tflite::Register_SOFTMAX_INT8_INT16());
  op_resolver->AddSvdf();

  return new (benchmark_runner_buffer)
      KeywordBenchmarkRunner(g_keyword_scrambled_model_data, op_resolver,
                             tensor_arena, kTensorArenaSize, profiler);
}

void KeywordRunNIerations(int iterations, const char* tag,
                          KeywordBenchmarkRunner& benchmark_runner,
                          MicroProfiler& profiler) {
  int32_t ticks = 0;
  for (int i = 0; i < iterations; ++i) {
    benchmark_runner.SetRandomInput(i);
    profiler.ClearEvents();
    benchmark_runner.RunSingleIteration();
    ticks += profiler.GetTotalTicks();
  }
  MicroPrintf("%s took %d ticks (%d ms)", tag, ticks, TicksToMs(ticks));
}

}  // namespace tflite

int main(int argc, char** argv) {
  tflite::InitializeTarget();
  tflite::MicroProfiler profiler;

  uint32_t event_handle = profiler.BeginEvent("InitializeKeywordRunner");
  tflite::KeywordBenchmarkRunner* benchmark_runner =
      CreateBenchmarkRunner(&profiler);
  profiler.EndEvent(event_handle);
  profiler.Log();
  MicroPrintf("");  // null MicroPrintf serves as a newline.

  tflite::KeywordRunNIerations(1, "KeywordRunNIerations(1)", *benchmark_runner,
                               profiler);
  profiler.Log();
  MicroPrintf("");  // null MicroPrintf serves as a newline.

  tflite::KeywordRunNIerations(10, "KeywordRunNIerations(10)",
                               *benchmark_runner, profiler);
  MicroPrintf("");  // null MicroPrintf serves as a newline.

  benchmark_runner->PrintAllocations();
}
<|endoftext|>


<commit_before>#pragma once

#include <unistd.h>

#include "constants.hpp"
#include "local_datagram_client.hpp"
#include "userspace_defs.h"

class grabber_client final {
public:
  grabber_client(void) : client_(constants::get_grabber_socket_file_path()) {}

  void connect(void) {
    krbn_operation_type_connect data;
    data.console_user_server_pid = getpid();
    client_.send_to(reinterpret_cast<uint8_t*>(&data), sizeof(data));
  }

private:
  local_datagram_client client_;
};
<commit_msg>set operation_type manually<commit_after>#pragma once

#include <unistd.h>

#include "constants.hpp"
#include "local_datagram_client.hpp"
#include "userspace_defs.h"

class grabber_client final {
public:
  grabber_client(void) : client_(constants::get_grabber_socket_file_path()) {}

  void connect(void) {
    krbn_operation_type_connect data;
    data.operation_type = KRBN_OPERATION_TYPE_CONNECT;
    data.console_user_server_pid = getpid();
    client_.send_to(reinterpret_cast<uint8_t*>(&data), sizeof(data));
  }

private:
  local_datagram_client client_;
};
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "SnoopTest.h"

class UpBroadcastListener:
  public virtual EventReceiver
{
public:
  virtual void SimpleCall(void) {}
};

class SnoopTestBase:
  public UpBroadcastListener
{
public:
  SnoopTestBase(void):
    m_simpleCall(false)
  {}

  bool m_simpleCall;

  void SimpleCall(void) override {
    m_simpleCall = true;
  }
};

class Firer:
  public EventSender<UpBroadcastListener>
{
public:
  void DoFire(void) {
    Fire(&UpBroadcastListener::SimpleCall)();
  };
};

class ChildMember:
  public SnoopTestBase
{};

class ParentMember:
  public SnoopTestBase
{
};

class IgnoredParentMember:
  public SnoopTestBase
{
};

class Disallowed:
  public ContextMember,
  public UpBroadcastListener
{
};

class DisallowedGeneric:
  public UpBroadcastListener
{
};

TEST_F(SnoopTest, VerifySimpleSnoop) {
  // Create the parent listener:
  AutoRequired<ParentMember> parentMember;

  // This listener instance shouldn't get any messages:
  AutoRequired<IgnoredParentMember> ignored;

  {
    // Create the child context and insert the child member:
    AutoCreateContext child;
    CurrentContextPusher pshr(child);
    AutoRequired<ChildMember> childMember;

    // Snoop
    child->Snoop(parentMember);

    // Now fire an event from the child:
    AutoRequired<Firer> firer;
    firer->DoFire();

    // Verify that the child itself got the message:
    EXPECT_TRUE(childMember->m_simpleCall) << "Message not received by another member of the same context";
  }

  // Verify that the parent got the message:
  EXPECT_TRUE(parentMember->m_simpleCall) << "Parent context snooper didn't receive a message broadcast by the child context";

  // Verify that the OTHER member got nothing:
  EXPECT_FALSE(ignored->m_simpleCall) << "A member in a parent context received a child-context message even though it didn't request to snoop that context";
}

TEST_F(SnoopTest, DetectDisallowedContextMember) {
  // Create two child contexts:
  AutoCreateContext sibling1;
  AutoCreateContext sibling2;

  // Create a member of the first context, and try to use it to snoop the second context:
  {
    CurrentContextPusher pshr(sibling1);
    AutoRequired<Disallowed> disallow;

    EXPECT_THROW(sibling2->Snoop(disallow), std::runtime_error);
  }
}

TEST_F(SnoopTest, DetectDisallowedGeneralType) {
  // Create two child contexts:
  AutoCreateContext sibling1;
  AutoCreateContext sibling2;

  // Create a member again, but this time, use the generic type so we can't use a context membership check
  {
    CurrentContextPusher pshr(sibling1);
    AutoRequired<DisallowedGeneric> disallowGeneric;

    EXPECT_THROW(sibling2->Snoop(disallowGeneric), std::runtime_error);
  }
}<commit_msg>Adding a unit test for Unsnoop<commit_after>#include "stdafx.h"
#include "SnoopTest.h"

class UpBroadcastListener:
  public virtual EventReceiver
{
public:
  virtual void SimpleCall(void) {}
};

class SnoopTestBase:
  public UpBroadcastListener
{
public:
  SnoopTestBase(void):
    m_simpleCall(false)
  {}

  bool m_simpleCall;

  void SimpleCall(void) override {
    m_simpleCall = true;
  }
};

class Firer:
  public EventSender<UpBroadcastListener>
{
public:
  void DoFire(void) {
    Fire(&UpBroadcastListener::SimpleCall)();
  };
};

class ChildMember:
  public SnoopTestBase
{};

class ParentMember:
  public SnoopTestBase
{
};

class IgnoredParentMember:
  public SnoopTestBase
{
};

class Disallowed:
  public ContextMember,
  public UpBroadcastListener
{
};

class DisallowedGeneric:
  public UpBroadcastListener
{
};

TEST_F(SnoopTest, VerifySimpleSnoop) {
  // Create the parent listener:
  AutoRequired<ParentMember> parentMember;

  // This listener instance shouldn't get any messages:
  AutoRequired<IgnoredParentMember> ignored;

  {
    // Create the child context and insert the child member:
    AutoCreateContext child;
    CurrentContextPusher pshr(child);
    AutoRequired<ChildMember> childMember;

    // Snoop
    child->Snoop(parentMember);

    // Now fire an event from the child:
    AutoRequired<Firer> firer;
    firer->DoFire();

    // Verify that the child itself got the message:
    EXPECT_TRUE(childMember->m_simpleCall) << "Message not received by another member of the same context";
  }

  // Verify that the parent got the message:
  EXPECT_TRUE(parentMember->m_simpleCall) << "Parent context snooper didn't receive a message broadcast by the child context";

  // Verify that the OTHER member got nothing:
  EXPECT_FALSE(ignored->m_simpleCall) << "A member in a parent context received a child-context message even though it didn't request to snoop that context";
}

TEST_F(SnoopTest, VerifyUnsnoop) {
  // Create a child context to snoop:
  AutoCreateContext snoopy;
  AutoRequired<ParentMember> parentMember;

  // Add a member to be snooped:
  {
    CurrentContextPusher pshr(snoopy);
    AutoRequired<ChildMember> childMember;

    // Snoop, unsnoop:
    snoopy->Snoop(parentMember);
    snoopy->Unsnoop(parentMember);

    // Fire one event:
    AutoRequired<Firer> firer;
    firer->DoFire();

    // The local listener should have gotten something
    EXPECT_TRUE(childMember->m_simpleCall) << "Message not received by a local listener after Unsnoop call";
  }

  EXPECT_FALSE(parentMember->m_simpleCall) << "ParentMember snooper received an event, even after an Unsnoop call was made";
}

TEST_F(SnoopTest, DetectDisallowedContextMember) {
  // Create two child contexts:
  AutoCreateContext sibling1;
  AutoCreateContext sibling2;

  // Create a member of the first context, and try to use it to snoop the second context:
  {
    CurrentContextPusher pshr(sibling1);
    AutoRequired<Disallowed> disallow;

    EXPECT_THROW(sibling2->Snoop(disallow), std::runtime_error);
  }
}

TEST_F(SnoopTest, DetectDisallowedGeneralType) {
  // Create two child contexts:
  AutoCreateContext sibling1;
  AutoCreateContext sibling2;

  // Create a member again, but this time, use the generic type so we can't use a context membership check
  {
    CurrentContextPusher pshr(sibling1);
    AutoRequired<DisallowedGeneric> disallowGeneric;

    EXPECT_THROW(sibling2->Snoop(disallowGeneric), std::runtime_error);
  }
}<|endoftext|>


<commit_before>#include <stan/math/prim/mat.hpp>
#include <gtest/gtest.h>

#ifdef STAN_OPENCL
#include <stan/math/opencl/opencl_context.hpp>
#include <stan/math/opencl/multiply.hpp>
#include <stan/math/opencl/copy.hpp>
#include <stan/math/opencl/lower_tri_inverse.hpp>
#include <boost/random/mersenne_twister.hpp>
#endif

#define EXPECT_MATRIX_NEAR(A, B, DELTA) \
  for (int i = 0; i < A.size(); i++)    \
    EXPECT_NEAR(A(i), B(i), DELTA);

TEST(MathMatrix, mdivide_left_tri_val) {
  using stan::math::mdivide_left_tri;
  stan::math::matrix_d Ad(2, 2);
  stan::math::matrix_d Ad_inv(2, 2);
  stan::math::matrix_d I;

  Ad << 2.0, 0.0, 5.0, 7.0;

  I = mdivide_left_tri<Eigen::Lower>(Ad, Ad);
  EXPECT_NEAR(1.0, I(0, 0), 1.0E-12);
  EXPECT_NEAR(0.0, I(0, 1), 1.0E-12);
  EXPECT_NEAR(0.0, I(1, 0), 1.0E-12);
  EXPECT_NEAR(1.0, I(1, 1), 1.0e-12);

  Ad_inv = mdivide_left_tri<Eigen::Lower>(Ad);
  I = Ad * Ad_inv;
  EXPECT_NEAR(1.0, I(0, 0), 1.0E-12);
  EXPECT_NEAR(0.0, I(0, 1), 1.0E-12);
  EXPECT_NEAR(0.0, I(1, 0), 1.0E-12);
  EXPECT_NEAR(1.0, I(1, 1), 1.0e-12);

  Ad << 2.0, 3.0, 0.0, 7.0;

  I = mdivide_left_tri<Eigen::Upper>(Ad, Ad);
  EXPECT_NEAR(1.0, I(0, 0), 1.0E-12);
  EXPECT_NEAR(0.0, I(0, 1), 1.0E-12);
  EXPECT_NEAR(0.0, I(1, 0), 1.0E-12);
  EXPECT_NEAR(1.0, I(1, 1), 1.0e-12);
}

#ifdef STAN_OPENCL
void mdivide_left_tri_lower_cl_test(int size) {
  boost::random::mt19937 rng;
  auto m1 = stan::math::matrix_d(size, size);
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < i; j++) {
      m1(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
    m1(i, i) = 20.0;
    for (int j = i + 1; j < size; j++) {
      m1(i, j) = 0.0;
    }
  }

  stan::math::opencl_context.tuning_opts().lower_tri_inverse_size_worth_transfer
      = size * 2;

  auto m1_cpu = stan::math::mdivide_left_tri<Eigen::Lower>(m1);

  stan::math::opencl_context.tuning_opts().lower_tri_inverse_size_worth_transfer
      = 0;

  auto m1_cl = stan::math::mdivide_left_tri<Eigen::Lower>(m1);

  EXPECT_MATRIX_NEAR(m1_cpu, m1_cl, 1E-8);
}
TEST(MathMatrixCL, mvidide_left_tri_lower_cl_small) {
  mvidive_left_tri_lower_cl_test(3);
}
TEST(MathMatrixCL, mvidide_left_tri_lower_cl_mid) {
  mvidive_left_tri_lower_cl_test(100);
}
TEST(MathMatrixCL, mvidide_left_tri_lower_cl_big) {
  mvidive_left_tri_lower_cl_test(500);
}

void mvidive_left_tri_upper_cl_test(int size) {
  boost::random::mt19937 rng;
  auto m1 = stan::math::matrix_d(size, size);
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < i; j++) {
      m1(i, j) = 0.0;
    }
    m1(i, i) = 20.0;
    for (int j = i + 1; j < size; j++) {
      m1(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
  }

  stan::math::opencl_context.tuning_opts().lower_tri_inverse_size_worth_transfer
      = size * 2;

  auto m1_cpu = stan::math::mdivide_left_tri<Eigen::Upper>(m1);

  stan::math::opencl_context.tuning_opts().lower_tri_inverse_size_worth_transfer
      = 0;

  auto m1_cl = stan::math::mdivide_left_tri<Eigen::Upper>(m1);

  EXPECT_MATRIX_NEAR(m1_cpu, m1_cl, 1E-8);
}
TEST(MathMatrixCL, mvidide_left_tri_upper_cl_small) {
  mvidive_left_tri_upper_cl_test(3);
}
TEST(MathMatrixCL, mvidide_left_tri_upper_cl_mid) {
  mvidive_left_tri_upper_cl_test(100);
}
TEST(MathMatrixCL, mvidide_left_tri_upper_cl_big) {
  mvidive_left_tri_upper_cl_test(500);
}

void mvidive_left_tri_cl_test(int size) {
  boost::random::mt19937 rng;
  auto m1 = stan::math::matrix_d(size, size);
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < i; j++) {
      m1(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
    m1(i, i) = 20.0;
    for (int j = i + 1; j < size; j++) {
      m1(i, j) = 0.0;
    }
  }

  stan::math::opencl_context.tuning_opts().lower_tri_inverse_size_worth_transfer
      = size * 2;

  auto m1_cpu = stan::math::mdivide_left_tri<Eigen::Lower>(m1, m1);

  stan::math::opencl_context.tuning_opts().lower_tri_inverse_size_worth_transfer
      = 0;

  auto m1_cl = stan::math::mdivide_left_tri<Eigen::Lower>(m1, m1);

  EXPECT_MATRIX_NEAR(m1_cpu, m1_cl, 1E-8);
}
TEST(MathMatrixCL, mvidide_left_tri_cl_small) { mvidive_left_tri_cl_test(3); }
TEST(MathMatrixCL, mvidide_left_tri_cl_mid) { mvidive_left_tri_cl_test(100); }
TEST(MathMatrixCL, mvidide_left_tri_cl_big) { mvidive_left_tri_cl_test(500); }

#endif
<commit_msg>fixed mdivide typo<commit_after>#include <stan/math/prim/mat.hpp>
#include <gtest/gtest.h>

#ifdef STAN_OPENCL
#include <stan/math/opencl/opencl_context.hpp>
#include <stan/math/opencl/multiply.hpp>
#include <stan/math/opencl/copy.hpp>
#include <stan/math/opencl/lower_tri_inverse.hpp>
#include <boost/random/mersenne_twister.hpp>
#endif

#define EXPECT_MATRIX_NEAR(A, B, DELTA) \
  for (int i = 0; i < A.size(); i++)    \
    EXPECT_NEAR(A(i), B(i), DELTA);

TEST(MathMatrix, mdivide_left_tri_val) {
  using stan::math::mdivide_left_tri;
  stan::math::matrix_d Ad(2, 2);
  stan::math::matrix_d Ad_inv(2, 2);
  stan::math::matrix_d I;

  Ad << 2.0, 0.0, 5.0, 7.0;

  I = mdivide_left_tri<Eigen::Lower>(Ad, Ad);
  EXPECT_NEAR(1.0, I(0, 0), 1.0E-12);
  EXPECT_NEAR(0.0, I(0, 1), 1.0E-12);
  EXPECT_NEAR(0.0, I(1, 0), 1.0E-12);
  EXPECT_NEAR(1.0, I(1, 1), 1.0e-12);

  Ad_inv = mdivide_left_tri<Eigen::Lower>(Ad);
  I = Ad * Ad_inv;
  EXPECT_NEAR(1.0, I(0, 0), 1.0E-12);
  EXPECT_NEAR(0.0, I(0, 1), 1.0E-12);
  EXPECT_NEAR(0.0, I(1, 0), 1.0E-12);
  EXPECT_NEAR(1.0, I(1, 1), 1.0e-12);

  Ad << 2.0, 3.0, 0.0, 7.0;

  I = mdivide_left_tri<Eigen::Upper>(Ad, Ad);
  EXPECT_NEAR(1.0, I(0, 0), 1.0E-12);
  EXPECT_NEAR(0.0, I(0, 1), 1.0E-12);
  EXPECT_NEAR(0.0, I(1, 0), 1.0E-12);
  EXPECT_NEAR(1.0, I(1, 1), 1.0e-12);
}

#ifdef STAN_OPENCL
void mdivide_left_tri_lower_cl_test(int size) {
  boost::random::mt19937 rng;
  auto m1 = stan::math::matrix_d(size, size);
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < i; j++) {
      m1(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
    m1(i, i) = 20.0;
    for (int j = i + 1; j < size; j++) {
      m1(i, j) = 0.0;
    }
  }

  stan::math::opencl_context.tuning_opts().lower_tri_inverse_size_worth_transfer
      = size * 2;

  auto m1_cpu = stan::math::mdivide_left_tri<Eigen::Lower>(m1);

  stan::math::opencl_context.tuning_opts().lower_tri_inverse_size_worth_transfer
      = 0;

  auto m1_cl = stan::math::mdivide_left_tri<Eigen::Lower>(m1);

  EXPECT_MATRIX_NEAR(m1_cpu, m1_cl, 1E-8);
}
TEST(MathMatrixCL, mdivide_left_tri_lower_cl_small) {
  mdivide_left_tri_lower_cl_test(3);
}
TEST(MathMatrixCL, mdivide_left_tri_lower_cl_mid) {
  mdivide_left_tri_lower_cl_test(100);
}
TEST(MathMatrixCL, mdivide_left_tri_lower_cl_big) {
  mdivide_left_tri_lower_cl_test(500);
}

void mdivide_left_tri_upper_cl_test(int size) {
  boost::random::mt19937 rng;
  auto m1 = stan::math::matrix_d(size, size);
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < i; j++) {
      m1(i, j) = 0.0;
    }
    m1(i, i) = 20.0;
    for (int j = i + 1; j < size; j++) {
      m1(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
  }

  stan::math::opencl_context.tuning_opts().lower_tri_inverse_size_worth_transfer
      = size * 2;

  auto m1_cpu = stan::math::mdivide_left_tri<Eigen::Upper>(m1);

  stan::math::opencl_context.tuning_opts().lower_tri_inverse_size_worth_transfer
      = 0;

  auto m1_cl = stan::math::mdivide_left_tri<Eigen::Upper>(m1);

  EXPECT_MATRIX_NEAR(m1_cpu, m1_cl, 1E-8);
}
TEST(MathMatrixCL, mdivide_left_tri_upper_cl_small) {
  mdivide_left_tri_upper_cl_test(3);
}
TEST(MathMatrixCL, mdivide_left_tri_upper_cl_mid) {
  mdivide_left_tri_upper_cl_test(100);
}
TEST(MathMatrixCL, mdivide_left_tri_upper_cl_big) {
  mdivide_left_tri_upper_cl_test(500);
}

void mdivide_left_tri_cl_test(int size) {
  boost::random::mt19937 rng;
  auto m1 = stan::math::matrix_d(size, size);
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < i; j++) {
      m1(i, j) = stan::math::uniform_rng(-5, 5, rng);
    }
    m1(i, i) = 20.0;
    for (int j = i + 1; j < size; j++) {
      m1(i, j) = 0.0;
    }
  }

  stan::math::opencl_context.tuning_opts().lower_tri_inverse_size_worth_transfer
      = size * 2;

  auto m1_cpu = stan::math::mdivide_left_tri<Eigen::Lower>(m1, m1);

  stan::math::opencl_context.tuning_opts().lower_tri_inverse_size_worth_transfer
      = 0;

  auto m1_cl = stan::math::mdivide_left_tri<Eigen::Lower>(m1, m1);

  EXPECT_MATRIX_NEAR(m1_cpu, m1_cl, 1E-8);
}
TEST(MathMatrixCL, mdivide_left_tri_cl_small) { mdivide_left_tri_cl_test(3); }
TEST(MathMatrixCL, mdivide_left_tri_cl_mid) { mdivide_left_tri_cl_test(100); }
TEST(MathMatrixCL, mdivide_left_tri_cl_big) { mdivide_left_tri_cl_test(500); }
#endif
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "Game.h"

int Game::MainLoop()
{
	HRESULT hRes = 0;
	int res = 0;

	RECT rect;
	SetRect(&rect, 10, 10, 200, 50);

	int fps = 0;
	int frameCount = 0;

	double dt = 0;
	double dtAcc = 0;

	LARGE_INTEGER accTimePrecStart;
	LARGE_INTEGER accTimePrecEnd;
	LARGE_INTEGER accTimePrecFreq;
	QueryPerformanceFrequency(&accTimePrecFreq);

	while (true)
	{
		QueryPerformanceCounter(&accTimePrecStart);

		if (PeekMessage(&RenderDeviceManager::msg, NULL, 0, 0, PM_REMOVE))
		{
			if (RenderDeviceManager::msg.message == WM_QUIT)
				break;
			TranslateMessage(&RenderDeviceManager::msg);
			DispatchMessage(&RenderDeviceManager::msg);
		}

		// Check render device
		if (!RenderDeviceManager::Created)
		{
			if (!OnNullRenderDevice())
				break;
		}

		// Check input device
		if (!InputDeviceManager::created)
		{
			InputDeviceManager::CreateInputDevices();
			if (!InputDeviceManager::created)
				break;
		}

		// Check inputs
		InputDeviceManager::CheckDevices();
		HandleKeyboard();
		HandleMouse();

		// Start scene drawing
		EnterCriticalSection(&worldLocker);
		RenderDeviceManager::RenderDevice->SetRenderTarget(0, RenderDeviceManager::DefaultRenderTarget);
		hRes = RenderDeviceManager::RenderDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(255, 0, 0, 0), 1.0f, 0);
		hRes = RenderDeviceManager::RenderDevice->BeginScene();

		if (WORLD != nullptr)
			Drawer::DrawWorld();

		// End scene drawing
		hRes = RenderDeviceManager::RenderDevice->EndScene();
		hRes = RenderDeviceManager::RenderDevice->Present(NULL, NULL, NULL, NULL);
		LeaveCriticalSection(&worldLocker);

		QueryPerformanceCounter(&accTimePrecEnd);
		dt = (double)(accTimePrecEnd.QuadPart - accTimePrecStart.QuadPart);
		dt /= accTimePrecFreq.QuadPart;

		frameCount++;
		dtAcc += dt;
		if (dtAcc > 1)
		{
			fps = frameCount;
			dtAcc -= 1;
			frameCount = 0;
		}
	}

	return RenderDeviceManager::msg.wParam;
}
<commit_msg>- nothing meaningful<commit_after>#include "stdafx.h"
#include "Game.h"

int Game::MainLoop()
{
	HRESULT hRes = 0;
	int res = 0;

	int fps = 0;
	int frameCount = 0;

	double dt = 0;
	double dtAcc = 0;

	LARGE_INTEGER accTimePrecStart;
	LARGE_INTEGER accTimePrecEnd;
	LARGE_INTEGER accTimePrecFreq;
	QueryPerformanceFrequency(&accTimePrecFreq);

	while (true)
	{
		QueryPerformanceCounter(&accTimePrecStart);

		if (PeekMessage(&RenderDeviceManager::msg, NULL, 0, 0, PM_REMOVE))
		{
			if (RenderDeviceManager::msg.message == WM_QUIT)
				break;
			TranslateMessage(&RenderDeviceManager::msg);
			DispatchMessage(&RenderDeviceManager::msg);
		}

		// Check render device
		if (!RenderDeviceManager::Created)
		{
			if (!OnNullRenderDevice())
				break;
		}

		// Check input device
		if (!InputDeviceManager::created)
		{
			InputDeviceManager::CreateInputDevices();
			if (!InputDeviceManager::created)
				break;
		}

		// Check inputs
		InputDeviceManager::CheckDevices();
		HandleKeyboard();
		HandleMouse();

		// Start scene drawing
		EnterCriticalSection(&worldLocker);
		RenderDeviceManager::RenderDevice->SetRenderTarget(0, RenderDeviceManager::DefaultRenderTarget);
		hRes = RenderDeviceManager::RenderDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(255, 0, 0, 0), 1.0f, 0);
		hRes = RenderDeviceManager::RenderDevice->BeginScene();

		if (WORLD != nullptr)
			Drawer::DrawWorld();

		// End scene drawing
		hRes = RenderDeviceManager::RenderDevice->EndScene();
		hRes = RenderDeviceManager::RenderDevice->Present(NULL, NULL, NULL, NULL);
		LeaveCriticalSection(&worldLocker);

		QueryPerformanceCounter(&accTimePrecEnd);
		dt = (double)(accTimePrecEnd.QuadPart - accTimePrecStart.QuadPart);
		dt /= accTimePrecFreq.QuadPart;

		frameCount++;
		dtAcc += dt;
		if (dtAcc > 1)
		{
			fps = frameCount;
			dtAcc -= 1;
			frameCount = 0;
		}
	}

	return RenderDeviceManager::msg.wParam;
}
<|endoftext|>