<commit_before>// Module:  Log4CPLUS
// File:    filter.cxx
// Created: 5/2003
// Author:  Tad E. Smith
//
//
// Copyright 2003-2015 Tad E. Smith
//
// 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 <log4cplus/spi/filter.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/stringhelper.h>
#include <log4cplus/helpers/property.h>
#include <log4cplus/spi/loggingevent.h>
#include <log4cplus/thread/syncprims-pub-impl.h>

#if defined (LOG4CPLUS_WITH_UNIT_TESTS)
#include <log4cplus/logger.h>
#include <catch.hpp>
#endif

namespace log4cplus { namespace spi {

///////////////////////////////////////////////////////////////////////////////
// global methods
///////////////////////////////////////////////////////////////////////////////

FilterResult
checkFilter(const Filter* filter, const InternalLoggingEvent& event)
{
    const Filter* currentFilter = filter;
    while(currentFilter) {
        FilterResult result = currentFilter->decide(event);
        if(result != NEUTRAL) {
            return result;
        }

        currentFilter = currentFilter->next.get();
    }

    return ACCEPT;
}

///////////////////////////////////////////////////////////////////////////////
// Filter implementation
///////////////////////////////////////////////////////////////////////////////

Filter::Filter()
{
}

Filter::~Filter()
{
}

void
Filter::appendFilter(FilterPtr filter)
{
    if (! next)
        next = filter;
    else
        next->appendFilter(filter);
}

///////////////////////////////////////////////////////////////////////////////
// DenyAllFilter implementation
///////////////////////////////////////////////////////////////////////////////

DenyAllFilter::DenyAllFilter ()
{ }

DenyAllFilter::DenyAllFilter (const helpers::Properties&)
{ }

FilterResult
DenyAllFilter::decide(const InternalLoggingEvent&) const
{
    return DENY;
}

///////////////////////////////////////////////////////////////////////////////
// LogLevelMatchFilter implementation
///////////////////////////////////////////////////////////////////////////////

LogLevelMatchFilter::LogLevelMatchFilter()
{
    init();
}

LogLevelMatchFilter::LogLevelMatchFilter(const helpers::Properties& properties)
{
    init();

    properties.getBool (acceptOnMatch, LOG4CPLUS_TEXT("AcceptOnMatch"));

    tstring const & log_level_to_match
        = properties.getProperty( LOG4CPLUS_TEXT("LogLevelToMatch") );
    logLevelToMatch = getLogLevelManager().fromString(log_level_to_match);
}

void
LogLevelMatchFilter::init()
{
    acceptOnMatch = true;
    logLevelToMatch = NOT_SET_LOG_LEVEL;
}

FilterResult
LogLevelMatchFilter::decide(const InternalLoggingEvent& event) const
{
    if(logLevelToMatch == NOT_SET_LOG_LEVEL) {
        return NEUTRAL;
    }

    bool matchOccured = (logLevelToMatch == event.getLogLevel());

    if(matchOccured) {
        return (acceptOnMatch ? ACCEPT : DENY);
    }
    else {
        return NEUTRAL;
    }
}

///////////////////////////////////////////////////////////////////////////////
// LogLevelRangeFilter implementation
///////////////////////////////////////////////////////////////////////////////

LogLevelRangeFilter::LogLevelRangeFilter()
{
    init();
}

LogLevelRangeFilter::LogLevelRangeFilter(const helpers::Properties& properties)
{
    init();

    properties.getBool (acceptOnMatch, LOG4CPLUS_TEXT("AcceptOnMatch"));

    tstring const & log_level_min
        = properties.getProperty( LOG4CPLUS_TEXT("LogLevelMin") );
    logLevelMin = getLogLevelManager().fromString(log_level_min);

    tstring const & log_level_max
        = properties.getProperty( LOG4CPLUS_TEXT("LogLevelMax") );
    logLevelMax = getLogLevelManager().fromString(log_level_max);
}

void
LogLevelRangeFilter::init()
{
    acceptOnMatch = true;
    logLevelMin = NOT_SET_LOG_LEVEL;
    logLevelMax = NOT_SET_LOG_LEVEL;
}

FilterResult
LogLevelRangeFilter::decide(const InternalLoggingEvent& event) const
{
    if((logLevelMin != NOT_SET_LOG_LEVEL) && (event.getLogLevel() < logLevelMin)) {
        // priority of event is less than minimum
        return DENY;
    }

    if((logLevelMax != NOT_SET_LOG_LEVEL) && (event.getLogLevel() > logLevelMax)) {
        // priority of event is greater than maximum
        return DENY;
    }

    if(acceptOnMatch) {
        // this filter set up to bypass later filters and always return
        // accept if priority in range
        return ACCEPT;
    }
    else {
        // event is ok for this filter; allow later filters to have a look...
        return NEUTRAL;
    }
}

///////////////////////////////////////////////////////////////////////////////
// StringMatchFilter implementation
///////////////////////////////////////////////////////////////////////////////

StringMatchFilter::StringMatchFilter()
{
    init();
}

StringMatchFilter::StringMatchFilter(const helpers::Properties& properties)
{
    init();

    properties.getBool (acceptOnMatch, LOG4CPLUS_TEXT("AcceptOnMatch"));
    stringToMatch = properties.getProperty( LOG4CPLUS_TEXT("StringToMatch") );
}

void
StringMatchFilter::init()
{
    acceptOnMatch = true;
}

FilterResult
StringMatchFilter::decide(const InternalLoggingEvent& event) const
{
    const tstring& message = event.getMessage();

    if(stringToMatch.empty () || message.empty ()) {
        return NEUTRAL;
    }

    if(message.find(stringToMatch) == tstring::npos) {
        return NEUTRAL;
    }
    else {  // we've got a match
        return (acceptOnMatch ? ACCEPT : DENY);
    }
}

//
//
//

FunctionFilter::FunctionFilter (FunctionFilter::Function f)
    : function (std::move (f))
{ }

FilterResult
FunctionFilter::decide(const InternalLoggingEvent& event) const
{
    return function (event);
}

#if defined (LOG4CPLUS_WITH_UNIT_TESTS)
CATCH_TEST_CASE ("Filter", "[filter]")
{
    FilterPtr filter;
    Logger log (Logger::getInstance (LOG4CPLUS_TEXT ("test")));
    InternalLoggingEvent info_ev (log.getName (), INFO_LOG_LEVEL,
        LOG4CPLUS_C_STR_TO_TSTRING (LOG4CPLUS_TEXT ("info log message")),
        __FILE__, __LINE__);
    InternalLoggingEvent error_ev (log.getName (), ERROR_LOG_LEVEL,
        LOG4CPLUS_C_STR_TO_TSTRING (LOG4CPLUS_TEXT ("error log message")),
        __FILE__, __LINE__);

    CATCH_SECTION ("deny all filter")
    {
        filter = new DenyAllFilter;
        CATCH_REQUIRE (filter->decide (info_ev) == DENY);
        CATCH_REQUIRE (checkFilter (filter.get (), info_ev) == DENY);
    }

    CATCH_SECTION ("log level match filter")
    {
        helpers::Properties props;
        props.setProperty (LOG4CPLUS_TEXT("LogLevelToMatch"),
            LOG4CPLUS_TEXT ("INFO"));
        filter = new LogLevelMatchFilter (props);
        CATCH_REQUIRE (filter->decide (info_ev) == ACCEPT);
    }
}

#endif

} } // namespace log4cplus { namespace spi {
<commit_msg>Cover LogLeveLRangeFilter and StringMatchFilter by unit tests.<commit_after>// Module:  Log4CPLUS
// File:    filter.cxx
// Created: 5/2003
// Author:  Tad E. Smith
//
//
// Copyright 2003-2015 Tad E. Smith
//
// 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 <log4cplus/spi/filter.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/stringhelper.h>
#include <log4cplus/helpers/property.h>
#include <log4cplus/spi/loggingevent.h>
#include <log4cplus/thread/syncprims-pub-impl.h>

#if defined (LOG4CPLUS_WITH_UNIT_TESTS)
#include <log4cplus/logger.h>
#include <catch.hpp>
#endif

namespace log4cplus { namespace spi {

///////////////////////////////////////////////////////////////////////////////
// global methods
///////////////////////////////////////////////////////////////////////////////

FilterResult
checkFilter(const Filter* filter, const InternalLoggingEvent& event)
{
    const Filter* currentFilter = filter;
    while(currentFilter) {
        FilterResult result = currentFilter->decide(event);
        if(result != NEUTRAL) {
            return result;
        }

        currentFilter = currentFilter->next.get();
    }

    return ACCEPT;
}

///////////////////////////////////////////////////////////////////////////////
// Filter implementation
///////////////////////////////////////////////////////////////////////////////

Filter::Filter()
{
}

Filter::~Filter()
{
}

void
Filter::appendFilter(FilterPtr filter)
{
    if (! next)
        next = filter;
    else
        next->appendFilter(filter);
}

///////////////////////////////////////////////////////////////////////////////
// DenyAllFilter implementation
///////////////////////////////////////////////////////////////////////////////

DenyAllFilter::DenyAllFilter ()
{ }

DenyAllFilter::DenyAllFilter (const helpers::Properties&)
{ }

FilterResult
DenyAllFilter::decide(const InternalLoggingEvent&) const
{
    return DENY;
}

///////////////////////////////////////////////////////////////////////////////
// LogLevelMatchFilter implementation
///////////////////////////////////////////////////////////////////////////////

LogLevelMatchFilter::LogLevelMatchFilter()
{
    init();
}

LogLevelMatchFilter::LogLevelMatchFilter(const helpers::Properties& properties)
{
    init();

    properties.getBool (acceptOnMatch, LOG4CPLUS_TEXT("AcceptOnMatch"));

    tstring const & log_level_to_match
        = properties.getProperty( LOG4CPLUS_TEXT("LogLevelToMatch") );
    logLevelToMatch = getLogLevelManager().fromString(log_level_to_match);
}

void
LogLevelMatchFilter::init()
{
    acceptOnMatch = true;
    logLevelToMatch = NOT_SET_LOG_LEVEL;
}

FilterResult
LogLevelMatchFilter::decide(const InternalLoggingEvent& event) const
{
    if(logLevelToMatch == NOT_SET_LOG_LEVEL) {
        return NEUTRAL;
    }

    bool matchOccured = (logLevelToMatch == event.getLogLevel());

    if(matchOccured) {
        return (acceptOnMatch ? ACCEPT : DENY);
    }
    else {
        return NEUTRAL;
    }
}

///////////////////////////////////////////////////////////////////////////////
// LogLevelRangeFilter implementation
///////////////////////////////////////////////////////////////////////////////

LogLevelRangeFilter::LogLevelRangeFilter()
{
    init();
}

LogLevelRangeFilter::LogLevelRangeFilter(const helpers::Properties& properties)
{
    init();

    properties.getBool (acceptOnMatch, LOG4CPLUS_TEXT("AcceptOnMatch"));

    tstring const & log_level_min
        = properties.getProperty( LOG4CPLUS_TEXT("LogLevelMin") );
    logLevelMin = getLogLevelManager().fromString(log_level_min);

    tstring const & log_level_max
        = properties.getProperty( LOG4CPLUS_TEXT("LogLevelMax") );
    logLevelMax = getLogLevelManager().fromString(log_level_max);
}

void
LogLevelRangeFilter::init()
{
    acceptOnMatch = true;
    logLevelMin = NOT_SET_LOG_LEVEL;
    logLevelMax = NOT_SET_LOG_LEVEL;
}

FilterResult
LogLevelRangeFilter::decide(const InternalLoggingEvent& event) const
{
    LogLevel const eventLogLevel = event.getLogLevel ();
    if((logLevelMin != NOT_SET_LOG_LEVEL) && (eventLogLevel < logLevelMin)) {
        // priority of event is less than minimum
        return DENY;
    }

    if((logLevelMax != NOT_SET_LOG_LEVEL) && (eventLogLevel > logLevelMax)) {
        // priority of event is greater than maximum
        return DENY;
    }

    if(acceptOnMatch) {
        // this filter set up to bypass later filters and always return
        // accept if priority in range
        return ACCEPT;
    }
    else {
        // event is ok for this filter; allow later filters to have a look...
        return NEUTRAL;
    }
}

///////////////////////////////////////////////////////////////////////////////
// StringMatchFilter implementation
///////////////////////////////////////////////////////////////////////////////

StringMatchFilter::StringMatchFilter()
{
    init();
}

StringMatchFilter::StringMatchFilter(const helpers::Properties& properties)
{
    init();

    properties.getBool (acceptOnMatch, LOG4CPLUS_TEXT("AcceptOnMatch"));
    stringToMatch = properties.getProperty( LOG4CPLUS_TEXT("StringToMatch") );
}

void
StringMatchFilter::init()
{
    acceptOnMatch = true;
}

FilterResult
StringMatchFilter::decide(const InternalLoggingEvent& event) const
{
    const tstring& message = event.getMessage();

    if(stringToMatch.empty () || message.empty ()) {
        return NEUTRAL;
    }

    if(message.find(stringToMatch) == tstring::npos) {
        return NEUTRAL;
    }
    else {  // we've got a match
        return (acceptOnMatch ? ACCEPT : DENY);
    }
}

//
//
//

FunctionFilter::FunctionFilter (FunctionFilter::Function f)
    : function (std::move (f))
{ }

FilterResult
FunctionFilter::decide(const InternalLoggingEvent& event) const
{
    return function (event);
}

#if defined (LOG4CPLUS_WITH_UNIT_TESTS)
CATCH_TEST_CASE ("Filter", "[filter]")
{
    FilterPtr filter;
    Logger log (Logger::getInstance (LOG4CPLUS_TEXT ("test")));
    static InternalLoggingEvent const warn_ev (log.getName (), WARN_LOG_LEVEL,
        LOG4CPLUS_C_STR_TO_TSTRING (LOG4CPLUS_TEXT ("warn log message")),
        __FILE__, __LINE__);
    static InternalLoggingEvent const info_ev (log.getName (), INFO_LOG_LEVEL,
        LOG4CPLUS_C_STR_TO_TSTRING (LOG4CPLUS_TEXT ("info log message")),
        __FILE__, __LINE__);
    static InternalLoggingEvent const empty_ev (log.getName (), INFO_LOG_LEVEL,
        LOG4CPLUS_C_STR_TO_TSTRING (LOG4CPLUS_TEXT ("")),
        __FILE__, __LINE__);
    static InternalLoggingEvent const error_ev (log.getName (), ERROR_LOG_LEVEL,
        LOG4CPLUS_C_STR_TO_TSTRING (LOG4CPLUS_TEXT ("error log message")),
        __FILE__, __LINE__);
    static InternalLoggingEvent const fatal_ev (log.getName (), FATAL_LOG_LEVEL,
        LOG4CPLUS_C_STR_TO_TSTRING (LOG4CPLUS_TEXT ("fatal log message")),
        __FILE__, __LINE__);

    CATCH_SECTION ("deny all filter")
    {
        filter = new DenyAllFilter;
        CATCH_REQUIRE (filter->decide (info_ev) == DENY);
        CATCH_REQUIRE (checkFilter (filter.get (), info_ev) == DENY);
    }

    CATCH_SECTION ("log level match filter")
    {
        CATCH_SECTION ("accept level")
        {
            helpers::Properties props;
            props.setProperty (LOG4CPLUS_TEXT ("LogLevelToMatch"),
                LOG4CPLUS_TEXT ("INFO"));
            filter = new LogLevelMatchFilter (props);
            CATCH_REQUIRE (filter->decide (info_ev) == ACCEPT);
            CATCH_REQUIRE (filter->decide (error_ev) == NEUTRAL);
        }

        CATCH_SECTION ("deny level")
        {
            helpers::Properties props;
            props.setProperty (LOG4CPLUS_TEXT ("LogLevelToMatch"),
                LOG4CPLUS_TEXT ("INFO"));
            props.setProperty (LOG4CPLUS_TEXT ("AcceptOnMatch"),
                LOG4CPLUS_TEXT ("false"));
            filter = new LogLevelMatchFilter (props);
            CATCH_REQUIRE (filter->decide (info_ev) == DENY);
            CATCH_REQUIRE (filter->decide (error_ev) == NEUTRAL);
        }
    }

    CATCH_SECTION ("log level range filter")
    {
        CATCH_SECTION ("accept in range")
        {
            helpers::Properties props;
            props.setProperty (LOG4CPLUS_TEXT ("LogLevelMin"),
                LOG4CPLUS_TEXT ("WARN"));
            props.setProperty (LOG4CPLUS_TEXT ("LogLevelMax"),
                LOG4CPLUS_TEXT ("ERROR"));
            filter = new LogLevelRangeFilter (props);
            CATCH_REQUIRE (filter->decide (info_ev) == DENY);
            CATCH_REQUIRE (filter->decide (warn_ev) == ACCEPT);
            CATCH_REQUIRE (filter->decide (error_ev) == ACCEPT);
            CATCH_REQUIRE (filter->decide (fatal_ev) == DENY);
        }

        CATCH_SECTION ("deny out of range")
        {
            helpers::Properties props;
            props.setProperty (LOG4CPLUS_TEXT ("LogLevelMin"),
                LOG4CPLUS_TEXT ("WARN"));
            props.setProperty (LOG4CPLUS_TEXT ("LogLevelMax"),
                LOG4CPLUS_TEXT ("ERROR"));
            props.setProperty (LOG4CPLUS_TEXT ("AcceptOnMatch"),
                LOG4CPLUS_TEXT ("false"));
            filter = new LogLevelRangeFilter (props);
            CATCH_REQUIRE (filter->decide (info_ev) == DENY);
            CATCH_REQUIRE (filter->decide (warn_ev) == NEUTRAL);
            CATCH_REQUIRE (filter->decide (error_ev) == NEUTRAL);
            CATCH_REQUIRE (filter->decide (fatal_ev) == DENY);
        }
    }

    CATCH_SECTION ("string match filter")
    {
        CATCH_SECTION ("empty string to match is neutral")
        {
            filter = new StringMatchFilter;
            CATCH_REQUIRE (filter->decide (info_ev) == NEUTRAL);
            CATCH_REQUIRE (filter->decide (error_ev) == NEUTRAL);
        }

        CATCH_SECTION ("not found is neutral")
        {
            helpers::Properties props;
            props.setProperty (LOG4CPLUS_TEXT ("StringToMatch"),
                LOG4CPLUS_TEXT ("nonexistent"));
            filter = new StringMatchFilter (props);
            CATCH_REQUIRE (filter->decide (info_ev) == NEUTRAL);
            CATCH_REQUIRE (filter->decide (error_ev) == NEUTRAL);
        }

        CATCH_SECTION ("empty event is neutral")
        {
            helpers::Properties props;
            props.setProperty (LOG4CPLUS_TEXT ("StringToMatch"),
                LOG4CPLUS_TEXT ("message"));
            filter = new StringMatchFilter (props);
            CATCH_REQUIRE (filter->decide (empty_ev) == NEUTRAL);
        }

        CATCH_SECTION ("deny on match")
        {
            helpers::Properties props;
            props.setProperty (LOG4CPLUS_TEXT ("StringToMatch"),
                LOG4CPLUS_TEXT ("message"));
            props.setProperty (LOG4CPLUS_TEXT ("AcceptOnMatch"),
                LOG4CPLUS_TEXT ("false"));
            filter = new StringMatchFilter (props);
            CATCH_REQUIRE (filter->decide (empty_ev) == NEUTRAL);
            CATCH_REQUIRE (filter->decide (info_ev) == DENY);
            CATCH_REQUIRE (filter->decide (warn_ev) == DENY);
        }
    }
}

#endif

} } // namespace log4cplus { namespace spi {
<|endoftext|>


<commit_before>/*
 * Copyright © 2012 Intel Corporation
 *
 * 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 (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include "main/core.h"
#include "ir.h"
#include "linker.h"
#include "ir_uniform.h"

/* These functions are put in a "private" namespace instead of being marked
 * static so that the unit tests can access them.  See
 * http://code.google.com/p/googletest/wiki/AdvancedGuide#Testing_Private_Code
 */
namespace linker {

gl_uniform_storage *
get_storage(gl_uniform_storage *storage, unsigned num_storage,
	    const char *name)
{
   for (unsigned int i = 0; i < num_storage; i++) {
      if (strcmp(name, storage[i].name) == 0)
	 return &storage[i];
   }

   return NULL;
}

static unsigned
get_uniform_block_index(const gl_shader_program *shProg,
                        const char *uniformBlockName)
{
   for (unsigned i = 0; i < shProg->NumBufferInterfaceBlocks; i++) {
      if (!strcmp(shProg->UniformBlocks[i].Name, uniformBlockName))
	 return i;
   }

   return GL_INVALID_INDEX;
}

void
copy_constant_to_storage(union gl_constant_value *storage,
			 const ir_constant *val,
			 const enum glsl_base_type base_type,
                         const unsigned int elements,
                         unsigned int boolean_true)
{
   for (unsigned int i = 0; i < elements; i++) {
      switch (base_type) {
      case GLSL_TYPE_UINT:
	 storage[i].u = val->value.u[i];
	 break;
      case GLSL_TYPE_INT:
      case GLSL_TYPE_SAMPLER:
	 storage[i].i = val->value.i[i];
	 break;
      case GLSL_TYPE_FLOAT:
	 storage[i].f = val->value.f[i];
	 break;
      case GLSL_TYPE_DOUBLE:
         /* XXX need to check on big-endian */
         storage[i * 2].u = *(uint32_t *)&val->value.d[i];
         storage[i * 2 + 1].u = *(((uint32_t *)&val->value.d[i]) + 1);
         break;
      case GLSL_TYPE_BOOL:
	 storage[i].b = val->value.b[i] ? boolean_true : 0;
	 break;
      case GLSL_TYPE_ARRAY:
      case GLSL_TYPE_STRUCT:
      case GLSL_TYPE_IMAGE:
      case GLSL_TYPE_ATOMIC_UINT:
      case GLSL_TYPE_INTERFACE:
      case GLSL_TYPE_VOID:
      case GLSL_TYPE_SUBROUTINE:
      case GLSL_TYPE_ERROR:
	 /* All other types should have already been filtered by other
	  * paths in the caller.
	  */
	 assert(!"Should not get here.");
	 break;
      }
   }
}

/**
 * Initialize an opaque uniform from the value of an explicit binding
 * qualifier specified in the shader.  Atomic counters are different because
 * they have no storage and should be handled elsewhere.
 */
void
set_opaque_binding(gl_shader_program *prog, const char *name, int binding)
{
   struct gl_uniform_storage *const storage =
      get_storage(prog->UniformStorage, prog->NumUniformStorage, name);

   if (storage == NULL) {
      assert(storage != NULL);
      return;
   }

   const unsigned elements = MAX2(storage->array_elements, 1);

   /* Section 4.4.4 (Opaque-Uniform Layout Qualifiers) of the GLSL 4.20 spec
    * says:
    *
    *     "If the binding identifier is used with an array, the first element
    *     of the array takes the specified unit and each subsequent element
    *     takes the next consecutive unit."
    */
   for (unsigned int i = 0; i < elements; i++) {
      storage->storage[i].i = binding + i;
   }

   for (int sh = 0; sh < MESA_SHADER_STAGES; sh++) {
      gl_shader *shader = prog->_LinkedShaders[sh];

      if (shader) {
         if (storage->type->base_type == GLSL_TYPE_SAMPLER &&
             storage->opaque[sh].active) {
            for (unsigned i = 0; i < elements; i++) {
               const unsigned index = storage->opaque[sh].index + i;
               shader->SamplerUnits[index] = storage->storage[i].i;
            }

         } else if (storage->type->base_type == GLSL_TYPE_IMAGE &&
                    storage->opaque[sh].active) {
            for (unsigned i = 0; i < elements; i++) {
               const unsigned index = storage->opaque[sh].index + i;
               shader->ImageUnits[index] = storage->storage[i].i;
            }
         }
      }
   }

   storage->initialized = true;
}

void
set_block_binding(gl_shader_program *prog, const char *block_name, int binding)
{
   const unsigned block_index = get_uniform_block_index(prog, block_name);

   if (block_index == GL_INVALID_INDEX) {
      assert(block_index != GL_INVALID_INDEX);
      return;
   }

      /* This is a field of a UBO.  val is the binding index. */
      for (int i = 0; i < MESA_SHADER_STAGES; i++) {
         int stage_index = prog->UniformBlockStageIndex[i][block_index];

         if (stage_index != -1) {
            struct gl_shader *sh = prog->_LinkedShaders[i];
            sh->UniformBlocks[stage_index].Binding = binding;
         }
      }
}

void
set_uniform_initializer(void *mem_ctx, gl_shader_program *prog,
			const char *name, const glsl_type *type,
                        ir_constant *val, unsigned int boolean_true)
{
   if (type->is_record()) {
      ir_constant *field_constant;

      field_constant = (ir_constant *)val->components.get_head();

      for (unsigned int i = 0; i < type->length; i++) {
	 const glsl_type *field_type = type->fields.structure[i].type;
	 const char *field_name = ralloc_asprintf(mem_ctx, "%s.%s", name,
					    type->fields.structure[i].name);
	 set_uniform_initializer(mem_ctx, prog, field_name,
                                 field_type, field_constant, boolean_true);
	 field_constant = (ir_constant *)field_constant->next;
      }
      return;
   } else if (type->is_array() && type->fields.array->is_record()) {
      const glsl_type *const element_type = type->fields.array;

      for (unsigned int i = 0; i < type->length; i++) {
	 const char *element_name = ralloc_asprintf(mem_ctx, "%s[%d]", name, i);

	 set_uniform_initializer(mem_ctx, prog, element_name,
                                 element_type, val->array_elements[i],
                                 boolean_true);
      }
      return;
   }

   struct gl_uniform_storage *const storage =
      get_storage(prog->UniformStorage,
                  prog->NumUniformStorage,
		  name);
   if (storage == NULL) {
      assert(storage != NULL);
      return;
   }

   if (val->type->is_array()) {
      const enum glsl_base_type base_type =
	 val->array_elements[0]->type->base_type;
      const unsigned int elements = val->array_elements[0]->type->components();
      unsigned int idx = 0;
      unsigned dmul = (base_type == GLSL_TYPE_DOUBLE) ? 2 : 1;

      assert(val->type->length >= storage->array_elements);
      for (unsigned int i = 0; i < storage->array_elements; i++) {
	 copy_constant_to_storage(& storage->storage[idx],
				  val->array_elements[i],
				  base_type,
                                  elements,
                                  boolean_true);

	 idx += elements * dmul;
      }
   } else {
      copy_constant_to_storage(storage->storage,
			       val,
			       val->type->base_type,
                               val->type->components(),
                               boolean_true);

      if (storage->type->is_sampler()) {
         for (int sh = 0; sh < MESA_SHADER_STAGES; sh++) {
            gl_shader *shader = prog->_LinkedShaders[sh];

            if (shader && storage->opaque[sh].active) {
               unsigned index = storage->opaque[sh].index;

               shader->SamplerUnits[index] = storage->storage[0].i;
            }
         }
      }
   }

   storage->initialized = true;
}
}

void
link_set_uniform_initializers(struct gl_shader_program *prog,
                              unsigned int boolean_true)
{
   void *mem_ctx = NULL;

   for (unsigned int i = 0; i < MESA_SHADER_STAGES; i++) {
      struct gl_shader *shader = prog->_LinkedShaders[i];

      if (shader == NULL)
	 continue;

      foreach_in_list(ir_instruction, node, shader->ir) {
	 ir_variable *const var = node->as_variable();

	 if (!var || (var->data.mode != ir_var_uniform &&
	     var->data.mode != ir_var_shader_storage))
	    continue;

	 if (!mem_ctx)
	    mem_ctx = ralloc_context(NULL);

         if (var->data.explicit_binding) {
            const glsl_type *const type = var->type;

            if (type->without_array()->is_sampler() ||
                type->without_array()->is_image()) {
               linker::set_opaque_binding(prog, var->name, var->data.binding);
            } else if (var->is_in_buffer_block()) {
               const glsl_type *const iface_type = var->get_interface_type();

               /* If the variable is an array and it is an interface instance,
                * we need to set the binding for each array element.  Just
                * checking that the variable is an array is not sufficient.
                * The variable could be an array element of a uniform block
                * that lacks an instance name.  For example:
                *
                *     uniform U {
                *         float f[4];
                *     };
                *
                * In this case "f" would pass is_in_buffer_block (above) and
                * type->is_array(), but it will fail is_interface_instance().
                */
               if (var->is_interface_instance() && var->type->is_array()) {
                  for (unsigned i = 0; i < var->type->length; i++) {
                     const char *name =
                        ralloc_asprintf(mem_ctx, "%s[%u]", iface_type->name, i);

                     /* Section 4.4.3 (Uniform Block Layout Qualifiers) of the
                      * GLSL 4.20 spec says:
                      *
                      *     "If the binding identifier is used with a uniform
                      *     block instanced as an array then the first element
                      *     of the array takes the specified block binding and
                      *     each subsequent element takes the next consecutive
                      *     uniform block binding point."
                      */
                     linker::set_block_binding(prog, name,
                                               var->data.binding + i);
                  }
               } else {
                  linker::set_block_binding(prog, iface_type->name,
                                            var->data.binding);
               }
            } else if (type->contains_atomic()) {
               /* we don't actually need to do anything. */
            } else {
               assert(!"Explicit binding not on a sampler, UBO or atomic.");
            }
         } else if (var->constant_value) {
            linker::set_uniform_initializer(mem_ctx, prog, var->name,
                                            var->type, var->constant_value,
                                            boolean_true);
         }
      }
   }

   ralloc_free(mem_ctx);
}
<commit_msg>glsl/linker: Use constant_initializer instead of constant_value to initialize uniforms<commit_after>/*
 * Copyright © 2012 Intel Corporation
 *
 * 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 (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include "main/core.h"
#include "ir.h"
#include "linker.h"
#include "ir_uniform.h"

/* These functions are put in a "private" namespace instead of being marked
 * static so that the unit tests can access them.  See
 * http://code.google.com/p/googletest/wiki/AdvancedGuide#Testing_Private_Code
 */
namespace linker {

gl_uniform_storage *
get_storage(gl_uniform_storage *storage, unsigned num_storage,
	    const char *name)
{
   for (unsigned int i = 0; i < num_storage; i++) {
      if (strcmp(name, storage[i].name) == 0)
	 return &storage[i];
   }

   return NULL;
}

static unsigned
get_uniform_block_index(const gl_shader_program *shProg,
                        const char *uniformBlockName)
{
   for (unsigned i = 0; i < shProg->NumBufferInterfaceBlocks; i++) {
      if (!strcmp(shProg->UniformBlocks[i].Name, uniformBlockName))
	 return i;
   }

   return GL_INVALID_INDEX;
}

void
copy_constant_to_storage(union gl_constant_value *storage,
			 const ir_constant *val,
			 const enum glsl_base_type base_type,
                         const unsigned int elements,
                         unsigned int boolean_true)
{
   for (unsigned int i = 0; i < elements; i++) {
      switch (base_type) {
      case GLSL_TYPE_UINT:
	 storage[i].u = val->value.u[i];
	 break;
      case GLSL_TYPE_INT:
      case GLSL_TYPE_SAMPLER:
	 storage[i].i = val->value.i[i];
	 break;
      case GLSL_TYPE_FLOAT:
	 storage[i].f = val->value.f[i];
	 break;
      case GLSL_TYPE_DOUBLE:
         /* XXX need to check on big-endian */
         storage[i * 2].u = *(uint32_t *)&val->value.d[i];
         storage[i * 2 + 1].u = *(((uint32_t *)&val->value.d[i]) + 1);
         break;
      case GLSL_TYPE_BOOL:
	 storage[i].b = val->value.b[i] ? boolean_true : 0;
	 break;
      case GLSL_TYPE_ARRAY:
      case GLSL_TYPE_STRUCT:
      case GLSL_TYPE_IMAGE:
      case GLSL_TYPE_ATOMIC_UINT:
      case GLSL_TYPE_INTERFACE:
      case GLSL_TYPE_VOID:
      case GLSL_TYPE_SUBROUTINE:
      case GLSL_TYPE_ERROR:
	 /* All other types should have already been filtered by other
	  * paths in the caller.
	  */
	 assert(!"Should not get here.");
	 break;
      }
   }
}

/**
 * Initialize an opaque uniform from the value of an explicit binding
 * qualifier specified in the shader.  Atomic counters are different because
 * they have no storage and should be handled elsewhere.
 */
void
set_opaque_binding(gl_shader_program *prog, const char *name, int binding)
{
   struct gl_uniform_storage *const storage =
      get_storage(prog->UniformStorage, prog->NumUniformStorage, name);

   if (storage == NULL) {
      assert(storage != NULL);
      return;
   }

   const unsigned elements = MAX2(storage->array_elements, 1);

   /* Section 4.4.4 (Opaque-Uniform Layout Qualifiers) of the GLSL 4.20 spec
    * says:
    *
    *     "If the binding identifier is used with an array, the first element
    *     of the array takes the specified unit and each subsequent element
    *     takes the next consecutive unit."
    */
   for (unsigned int i = 0; i < elements; i++) {
      storage->storage[i].i = binding + i;
   }

   for (int sh = 0; sh < MESA_SHADER_STAGES; sh++) {
      gl_shader *shader = prog->_LinkedShaders[sh];

      if (shader) {
         if (storage->type->base_type == GLSL_TYPE_SAMPLER &&
             storage->opaque[sh].active) {
            for (unsigned i = 0; i < elements; i++) {
               const unsigned index = storage->opaque[sh].index + i;
               shader->SamplerUnits[index] = storage->storage[i].i;
            }

         } else if (storage->type->base_type == GLSL_TYPE_IMAGE &&
                    storage->opaque[sh].active) {
            for (unsigned i = 0; i < elements; i++) {
               const unsigned index = storage->opaque[sh].index + i;
               shader->ImageUnits[index] = storage->storage[i].i;
            }
         }
      }
   }

   storage->initialized = true;
}

void
set_block_binding(gl_shader_program *prog, const char *block_name, int binding)
{
   const unsigned block_index = get_uniform_block_index(prog, block_name);

   if (block_index == GL_INVALID_INDEX) {
      assert(block_index != GL_INVALID_INDEX);
      return;
   }

      /* This is a field of a UBO.  val is the binding index. */
      for (int i = 0; i < MESA_SHADER_STAGES; i++) {
         int stage_index = prog->UniformBlockStageIndex[i][block_index];

         if (stage_index != -1) {
            struct gl_shader *sh = prog->_LinkedShaders[i];
            sh->UniformBlocks[stage_index].Binding = binding;
         }
      }
}

void
set_uniform_initializer(void *mem_ctx, gl_shader_program *prog,
			const char *name, const glsl_type *type,
                        ir_constant *val, unsigned int boolean_true)
{
   if (type->is_record()) {
      ir_constant *field_constant;

      field_constant = (ir_constant *)val->components.get_head();

      for (unsigned int i = 0; i < type->length; i++) {
	 const glsl_type *field_type = type->fields.structure[i].type;
	 const char *field_name = ralloc_asprintf(mem_ctx, "%s.%s", name,
					    type->fields.structure[i].name);
	 set_uniform_initializer(mem_ctx, prog, field_name,
                                 field_type, field_constant, boolean_true);
	 field_constant = (ir_constant *)field_constant->next;
      }
      return;
   } else if (type->is_array() && type->fields.array->is_record()) {
      const glsl_type *const element_type = type->fields.array;

      for (unsigned int i = 0; i < type->length; i++) {
	 const char *element_name = ralloc_asprintf(mem_ctx, "%s[%d]", name, i);

	 set_uniform_initializer(mem_ctx, prog, element_name,
                                 element_type, val->array_elements[i],
                                 boolean_true);
      }
      return;
   }

   struct gl_uniform_storage *const storage =
      get_storage(prog->UniformStorage,
                  prog->NumUniformStorage,
		  name);
   if (storage == NULL) {
      assert(storage != NULL);
      return;
   }

   if (val->type->is_array()) {
      const enum glsl_base_type base_type =
	 val->array_elements[0]->type->base_type;
      const unsigned int elements = val->array_elements[0]->type->components();
      unsigned int idx = 0;
      unsigned dmul = (base_type == GLSL_TYPE_DOUBLE) ? 2 : 1;

      assert(val->type->length >= storage->array_elements);
      for (unsigned int i = 0; i < storage->array_elements; i++) {
	 copy_constant_to_storage(& storage->storage[idx],
				  val->array_elements[i],
				  base_type,
                                  elements,
                                  boolean_true);

	 idx += elements * dmul;
      }
   } else {
      copy_constant_to_storage(storage->storage,
			       val,
			       val->type->base_type,
                               val->type->components(),
                               boolean_true);

      if (storage->type->is_sampler()) {
         for (int sh = 0; sh < MESA_SHADER_STAGES; sh++) {
            gl_shader *shader = prog->_LinkedShaders[sh];

            if (shader && storage->opaque[sh].active) {
               unsigned index = storage->opaque[sh].index;

               shader->SamplerUnits[index] = storage->storage[0].i;
            }
         }
      }
   }

   storage->initialized = true;
}
}

void
link_set_uniform_initializers(struct gl_shader_program *prog,
                              unsigned int boolean_true)
{
   void *mem_ctx = NULL;

   for (unsigned int i = 0; i < MESA_SHADER_STAGES; i++) {
      struct gl_shader *shader = prog->_LinkedShaders[i];

      if (shader == NULL)
	 continue;

      foreach_in_list(ir_instruction, node, shader->ir) {
	 ir_variable *const var = node->as_variable();

	 if (!var || (var->data.mode != ir_var_uniform &&
	     var->data.mode != ir_var_shader_storage))
	    continue;

	 if (!mem_ctx)
	    mem_ctx = ralloc_context(NULL);

         if (var->data.explicit_binding) {
            const glsl_type *const type = var->type;

            if (type->without_array()->is_sampler() ||
                type->without_array()->is_image()) {
               linker::set_opaque_binding(prog, var->name, var->data.binding);
            } else if (var->is_in_buffer_block()) {
               const glsl_type *const iface_type = var->get_interface_type();

               /* If the variable is an array and it is an interface instance,
                * we need to set the binding for each array element.  Just
                * checking that the variable is an array is not sufficient.
                * The variable could be an array element of a uniform block
                * that lacks an instance name.  For example:
                *
                *     uniform U {
                *         float f[4];
                *     };
                *
                * In this case "f" would pass is_in_buffer_block (above) and
                * type->is_array(), but it will fail is_interface_instance().
                */
               if (var->is_interface_instance() && var->type->is_array()) {
                  for (unsigned i = 0; i < var->type->length; i++) {
                     const char *name =
                        ralloc_asprintf(mem_ctx, "%s[%u]", iface_type->name, i);

                     /* Section 4.4.3 (Uniform Block Layout Qualifiers) of the
                      * GLSL 4.20 spec says:
                      *
                      *     "If the binding identifier is used with a uniform
                      *     block instanced as an array then the first element
                      *     of the array takes the specified block binding and
                      *     each subsequent element takes the next consecutive
                      *     uniform block binding point."
                      */
                     linker::set_block_binding(prog, name,
                                               var->data.binding + i);
                  }
               } else {
                  linker::set_block_binding(prog, iface_type->name,
                                            var->data.binding);
               }
            } else if (type->contains_atomic()) {
               /* we don't actually need to do anything. */
            } else {
               assert(!"Explicit binding not on a sampler, UBO or atomic.");
            }
         } else if (var->constant_initializer) {
            linker::set_uniform_initializer(mem_ctx, prog, var->name,
                                            var->type, var->constant_initializer,
                                            boolean_true);
         }
      }
   }

   ralloc_free(mem_ctx);
}
<|endoftext|>


<commit_before>//
// Created by Yihung Lee on 2018-12-01.
//

#include "BackTracking.hpp"

vector<string> BackTracking::letterCombinations(string digits) {
    if (digits.empty()) return {};
    const unordered_map<char, string> map{
            {'2', "abc"},
            {'3', "def"},
            {'4', "ghi"},
            {'5', "jkl"},
            {'6', "mno"},
            {'7', "pqrs"},
            {'8', "tuv"},
            {'9', "wxyz"},
    };
    vector<string> ans;
    letterCombinationsHelper(ans, digits, "", 0, map);
    return ans;
}

void BackTracking::letterCombinationsHelper(vector<string> &ans, const string digits, string res, int idx,
                                            const unordered_map<char, string> &map) {

    if (res.size() == digits.size()) {
        ans.push_back(res);
    } else {
        for (auto s : map.at(digits[idx])) {
            letterCombinationsHelper(ans, digits, res + s, idx + 1, map);
        }
    }
}

/**
 * Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
 */
vector<string> BackTracking::generateParenthesis(int n) {
    vector<string> ans;
    generateParenthesisHelper(n, n, "", ans);
    return ans;
}

void BackTracking::generateParenthesisHelper(int L, int R, string res, vector<string> &ans) {
    if (L == 0 && R == 0) {
        ans.push_back(res);
    } else if (L >=0 && L <= R) {
        generateParenthesisHelper(L - 1, R, res + '(', ans);
        generateParenthesisHelper(L, R - 1, res + ')', ans);
    }
}

void BackTracking::nextPermutation(vector<int>& nums){

}<commit_msg>// 31. Next Permutation<commit_after>//
// Created by Yihung Lee on 2018-12-01.
//

#include "BackTracking.hpp"

vector<string> BackTracking::letterCombinations(string digits) {
    if (digits.empty()) return {};
    const unordered_map<char, string> map{
            {'2', "abc"},
            {'3', "def"},
            {'4', "ghi"},
            {'5', "jkl"},
            {'6', "mno"},
            {'7', "pqrs"},
            {'8', "tuv"},
            {'9', "wxyz"},
    };
    vector<string> ans;
    letterCombinationsHelper(ans, digits, "", 0, map);
    return ans;
}

void BackTracking::letterCombinationsHelper(vector<string> &ans, const string digits, string res, int idx,
                                            const unordered_map<char, string> &map) {

    if (res.size() == digits.size()) {
        ans.push_back(res);
    } else {
        for (auto s : map.at(digits[idx])) {
            letterCombinationsHelper(ans, digits, res + s, idx + 1, map);
        }
    }
}

/**
 * Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
 */
vector<string> BackTracking::generateParenthesis(int n) {
    vector<string> ans;
    generateParenthesisHelper(n, n, "", ans);
    return ans;
}

void BackTracking::generateParenthesisHelper(int L, int R, string res, vector<string> &ans) {
    if (L == 0 && R == 0) {
        ans.push_back(res);
    } else if (L >= 0 && L <= R) {
        generateParenthesisHelper(L - 1, R, res + '(', ans);
        generateParenthesisHelper(L, R - 1, res + ')', ans);
    }
}

/**
 * http://www.cnblogs.com/grandyang/p/4428207.html
 */
void BackTracking::nextPermutation(vector<int> &nums) {
    int n = nums.size(), i = n - 2, j = n - 1;
    while (i >= 0 && nums[i] >= nums[i + 1]) --i;
    if (i >= 0) {
        while (nums[j] <= nums[i]) --j;
        swap(nums[i], nums[j]);
    }
    reverse(nums.begin() + i + 1, nums.end());
}<|endoftext|>


<commit_before>/*
  Copyright 2012 Larry Gritz and the other authors and contributors.
  All Rights Reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are
  met:
  * Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.
  * Neither the name of the software's owners nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

  (This is the Modified BSD License)
*/

#include "imageio.h"
#include "imagebuf.h"
#include "imagebufalgo.h"
#include "sysutil.h"
#include "argparse.h"
#include "ustring.h"
#include "strutil.h"
#include "timer.h"
#include "unittest.h"

#include <iostream>

OIIO_NAMESPACE_USING;

static bool verbose = false;
static int iterations = 1;
static int ntrials = 1;
static ustring input_filename;
static std::vector<char> buffer;
static ImageCache *imagecache = NULL;
static ImageSpec spec;

static int
parse_files (int argc, const char *argv[])
{
    input_filename = ustring(argv[0]);
    return 0;
}

static void
getargs (int argc, char *argv[])
{
    bool help = false;
    ArgParse ap;
    ap.options ("imagespeed_test\n"
                OIIO_INTRO_STRING "\n"
                "Usage:  imagespeed_test [options]",
                "%*", parse_files, "",
                "--help", &help, "Print help message",
                "-v", &verbose, "Verbose mode",
//                "--threads %d", &numthreads,
//                    ustring::format("Number of threads (default: %d)", numthreads).c_str(),
                "--iters %d", &iterations,
                    ustring::format("Number of iterations (default: %d)", iterations).c_str(),
                "--trials %d", &ntrials, "Number of trials",
//                "--wedge", &wedge, "Do a wedge test",
                NULL);
    if (ap.parse (argc, (const char**)argv) < 0) {
        std::cerr << ap.geterror() << std::endl;
        ap.usage ();
        exit (EXIT_FAILURE);
    }
    if (help) {
        ap.usage ();
        exit (EXIT_FAILURE);
    }
}

static void
time_read_image ()
{
    ImageInput *in = ImageInput::open (input_filename.c_str());
    ASSERT (in);
    in->read_image (TypeDesc::TypeFloat, &buffer[0]);
    in->close ();
    delete in;
}

static void
time_read_imagebuf ()
{
    ImageBuf ib (input_filename.string(), imagecache);
    ib.read (0, 0, true, TypeDesc::TypeFloat);
    imagecache->invalidate_all (true);
}

static void
time_ic_get_pixels ()
{
    imagecache->get_pixels (input_filename, 0, 0, spec.x, spec.x+spec.width,
                            spec.y, spec.y+spec.height,
                            spec.z, spec.z+spec.depth,
                            TypeDesc::TypeFloat, &buffer[0]);
    imagecache->invalidate_all (true);
}

int
main (int argc, char **argv)
{
    getargs (argc, argv);

    if (input_filename.empty()) {
        std::cout << "Error: Must supply a filename.\n";
        return -1;
    }

    imagecache = ImageCache::create ();
    imagecache->attribute ("forcefloat", 1);

    // Allocate a buffer big enough (for floats)
    bool ok = imagecache->get_imagespec (input_filename, spec);
    ASSERT (ok);
    imagecache->invalidate_all (true);  // Don't hold anything
    buffer.resize (spec.image_pixels()*spec.nchannels*sizeof(float), 0);

    {
        double t = time_trial (time_read_image, ntrials);
        std::cout << "image_read speed: " << Strutil::timeintervalformat(t,2) << "\n";
    }

    {
        double t = time_trial (time_read_imagebuf, ntrials);
        std::cout << "ImageBuf read speed: " << Strutil::timeintervalformat(t,2) << "\n";
    }

    {
        double t = time_trial (time_ic_get_pixels, ntrials);
        std::cout << "ImageCache get_pixels speed: " << Strutil::timeintervalformat(t,2) << "\n";
    }

    imagecache->invalidate_all (true);  // Don't hold anything

    ImageCache::destroy (imagecache);
    return unit_test_failures;
}
<commit_msg>More diagnostics in imagespeed_test to pinpoint bottlenecks<commit_after>/*
  Copyright 2012 Larry Gritz and the other authors and contributors.
  All Rights Reserved.

  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions are
  met:
  * Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.
  * Neither the name of the software's owners nor the names of its
  contributors may be used to endorse or promote products derived from
  this software without specific prior written permission.
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

  (This is the Modified BSD License)
*/

#include "imageio.h"
#include "imagebuf.h"
#include "imagebufalgo.h"
#include "sysutil.h"
#include "argparse.h"
#include "ustring.h"
#include "strutil.h"
#include "timer.h"
#include "unittest.h"

#include <iostream>

OIIO_NAMESPACE_USING;

static bool verbose = false;
static int iterations = 1;
static int ntrials = 1;
static ustring input_filename;
static std::vector<char> buffer;
static ImageCache *imagecache = NULL;
static ImageSpec spec;

static int
parse_files (int argc, const char *argv[])
{
    input_filename = ustring(argv[0]);
    return 0;
}

static void
getargs (int argc, char *argv[])
{
    bool help = false;
    ArgParse ap;
    ap.options ("imagespeed_test\n"
                OIIO_INTRO_STRING "\n"
                "Usage:  imagespeed_test [options]",
                "%*", parse_files, "",
                "--help", &help, "Print help message",
                "-v", &verbose, "Verbose mode",
//                "--threads %d", &numthreads,
//                    ustring::format("Number of threads (default: %d)", numthreads).c_str(),
                "--iters %d", &iterations,
                    ustring::format("Number of iterations (default: %d)", iterations).c_str(),
                "--trials %d", &ntrials, "Number of trials",
//                "--wedge", &wedge, "Do a wedge test",
                NULL);
    if (ap.parse (argc, (const char**)argv) < 0) {
        std::cerr << ap.geterror() << std::endl;
        ap.usage ();
        exit (EXIT_FAILURE);
    }
    if (help) {
        ap.usage ();
        exit (EXIT_FAILURE);
    }
}

static void
time_read_image ()
{
    ImageInput *in = ImageInput::open (input_filename.c_str());
    ASSERT (in);
    in->read_image (TypeDesc::TypeFloat, &buffer[0]);
    in->close ();
    delete in;
}

static void
time_read_scanline_at_a_time ()
{
    ImageInput *in = ImageInput::open (input_filename.c_str());
    ASSERT (in);
    const ImageSpec &spec (in->spec());
    size_t pixelsize = spec.nchannels * sizeof(float);
    imagesize_t scanlinesize = spec.width * pixelsize;
    for (int y = 0; y < spec.height;  ++y) {
        in->read_scanline (y+spec.y, 0, TypeDesc::TypeFloat,
                           &buffer[scanlinesize*y]);
    }
    in->close ();
    delete in;
}

static void
time_read_64_scanlines_at_a_time ()
{
    ImageInput *in = ImageInput::open (input_filename.c_str());
    ASSERT (in);
    const ImageSpec &spec (in->spec());
    size_t pixelsize = spec.nchannels * sizeof(float);
    imagesize_t scanlinesize = spec.width * pixelsize;
    for (int y = 0; y < spec.height;  y += 64) {
        in->read_scanlines (y+spec.y, std::min(y+spec.y+64, spec.y+spec.height),
                            0, TypeDesc::TypeFloat, &buffer[scanlinesize*y]);
    }
    in->close ();
    delete in;
}

static void
time_read_imagebuf ()
{
    ImageBuf ib (input_filename.string(), imagecache);
    ib.read (0, 0, true, TypeDesc::TypeFloat);
    imagecache->invalidate_all (true);
}

static void
time_ic_get_pixels ()
{
    imagecache->get_pixels (input_filename, 0, 0, spec.x, spec.x+spec.width,
                            spec.y, spec.y+spec.height,
                            spec.z, spec.z+spec.depth,
                            TypeDesc::TypeFloat, &buffer[0]);
    imagecache->invalidate_all (true);
}

int
main (int argc, char **argv)
{
    getargs (argc, argv);

    if (input_filename.empty()) {
        std::cout << "Error: Must supply a filename.\n";
        return -1;
    }

    imagecache = ImageCache::create ();
    imagecache->attribute ("forcefloat", 1);

    // Allocate a buffer big enough (for floats)
    bool ok = imagecache->get_imagespec (input_filename, spec, 0, 0, true);
    ASSERT (ok);
    imagecache->invalidate_all (true);  // Don't hold anything
    buffer.resize (spec.image_pixels()*spec.nchannels*sizeof(float), 0);

    {
        double t = time_trial (time_read_image, ntrials);
        std::cout << "read_image speed: " << Strutil::timeintervalformat(t,2) << "\n";
    }

    if (spec.tile_width == 0) {
        double t = time_trial (time_read_scanline_at_a_time, ntrials);
        std::cout << "read_scanline (1 at a time) speed: " << Strutil::timeintervalformat(t,2) << "\n";
    }

    if (spec.tile_width == 0) {
        double t = time_trial (time_read_64_scanlines_at_a_time, ntrials);
        std::cout << "read_scanlines (64 at a time) speed: " << Strutil::timeintervalformat(t,2) << "\n";
    }
    {
        imagecache->invalidate_all (true);  // Don't hold anything
        double t = time_trial (time_read_imagebuf, ntrials);
        std::cout << "ImageBuf read speed: " << Strutil::timeintervalformat(t,2) << "\n";
    }

    {
        imagecache->invalidate_all (true);  // Don't hold anything
        double t = time_trial (time_ic_get_pixels, ntrials);
        std::cout << "ImageCache get_pixels speed: " << Strutil::timeintervalformat(t,2) << "\n";
    }

    std::cout << "With autotile = 64:\n";
    imagecache->attribute ("autotile", 64);
    {
        imagecache->invalidate_all (true);  // Don't hold anything
        double t = time_trial (time_read_imagebuf, ntrials);
        std::cout << "ImageBuf read speed: " << Strutil::timeintervalformat(t,2) << "\n";
    }
    {
        imagecache->invalidate_all (true);  // Don't hold anything
        double t = time_trial (time_ic_get_pixels, ntrials);
        std::cout << "ImageCache get_pixels speed: " << Strutil::timeintervalformat(t,2) << "\n";
    }

    std::cout << "With autotile = 64, autoscanline = 1:\n";
    imagecache->attribute ("autotile", 64);
    imagecache->attribute ("autoscanline", 1);
    {
        imagecache->invalidate_all (true);  // Don't hold anything
        double t = time_trial (time_read_imagebuf, ntrials);
        std::cout << "ImageBuf read speed: " << Strutil::timeintervalformat(t,2) << "\n";
    }
    {
        imagecache->invalidate_all (true);  // Don't hold anything
        double t = time_trial (time_ic_get_pixels, ntrials);
        std::cout << "ImageCache get_pixels speed: " << Strutil::timeintervalformat(t,2) << "\n";
    }

    if (verbose)
        std::cout << "\n" << imagecache->getstats(2) << "\n";

    imagecache->invalidate_all (true);  // Don't hold anything

    ImageCache::destroy (imagecache);
    return unit_test_failures;
}
<|endoftext|>


<commit_before>#include "pokeyDevice.h"
#include <string.h>

PokeyDevice::PokeyDevice(sPoKeysNetworkDeviceSummary deviceSummary, uint8_t index)
{
    _pokey = PK_ConnectToNetworkDevice(&deviceSummary);
    _index = index;
    _userId = deviceSummary.UserID;
    _serialNumber = std::to_string(deviceSummary.SerialNumber);
    _firwareVersionMajorMajor = (deviceSummary.FirmwareVersionMajor >> 4) + 1;
    _firwareVersionMajor = deviceSummary.FirmwareVersionMajor & 0x0F;
    _firwareVersionMinor = deviceSummary.FirmwareVersionMinor;
    memcpy(&_ipAddress, &deviceSummary.IPaddress, 4);
    _hardwareType = deviceSummary.HWtype;
    _dhcp = deviceSummary.DHCP;

    loadPinConfiguration();
}

/**
 *   @brief  Default  destructor for PokeyDevice
 *
 *   @return nothing
 */
PokeyDevice::~PokeyDevice()
{
    PK_DisconnectDevice(_pokey);
}

std::string PokeyDevice::hardwareTypeString()
{
    if (_hardwareType == 31) {
        return "Pokey 57E";
    }
    return "Unknown";
}

bool PokeyDevice::validatePinCapability(int number, std::string type)
{
    // assert(_pokey);
    bool retVal = true;

    return retVal;
}}
}

uint32_t PokeyDevice::targetValue(std::string targetName, bool value)
{
    uint8_t pin = pinFromName(targetName) - 1;
    uint32_t retValue = PK_DigitalIOSetSingle(_pokey, pin, (uint8_t)value);

    if (retValue == PK_ERR_TRANSFER) {
        printf("----> PK_ERR_TRANSFER pin %d --> %d %d\n\n", pin, (uint8_t)value, retValue);
    }
    else if (retValue == PK_ERR_GENERIC) {
        printf("----> PK_ERR_GENERIC pin %d --> %d %d\n\n", pin, (uint8_t)value, retValue);
    }
    else if (retValue == PK_ERR_PARAMETER) {
        printf("----> PK_ERR_PARAMETER pin %d --> %d %d\n\n", pin, (uint8_t)value, retValue);
    }

    return retValue;
}

<commit_msg>deailing with pin IO<commit_after>#include "pokeyDevice.h"
#include <string.h>

PokeyDevice::PokeyDevice(sPoKeysNetworkDeviceSummary deviceSummary, uint8_t index)
{
    _pokey = PK_ConnectToNetworkDevice(&deviceSummary);
    _index = index;
    _userId = deviceSummary.UserID;
    _serialNumber = std::to_string(deviceSummary.SerialNumber);
    _firwareVersionMajorMajor = (deviceSummary.FirmwareVersionMajor >> 4) + 1;
    _firwareVersionMajor = deviceSummary.FirmwareVersionMajor & 0x0F;
    _firwareVersionMinor = deviceSummary.FirmwareVersionMinor;
    memcpy(&_ipAddress, &deviceSummary.IPaddress, 4);
    _hardwareType = deviceSummary.HWtype;
    _dhcp = deviceSummary.DHCP;

    loadPinConfiguration();
}

/**
 *   @brief  Default  destructor for PokeyDevice
 *
 *   @return nothing
 */
PokeyDevice::~PokeyDevice()
{
    PK_DisconnectDevice(_pokey);
}

std::string PokeyDevice::hardwareTypeString()
{
    if (_hardwareType == 31) {
        return "Pokey 57E";
    }
    return "Unknown";
}

bool PokeyDevice::validatePinCapability(int number, std::string type)
{
    // assert(_pokey);
    bool retVal = true;

    return retVal;
}}
}

uint32_t PokeyDevice::targetValue(std::string targetName, bool value)
{
    uint8_t pin = pinFromName(targetName) - 1;
    uint32_t retValue = PK_DigitalIOSetSingle(_pokey, pin, (uint8_t)value);

    if (retValue == PK_ERR_TRANSFER) {
        printf("----> PK_ERR_TRANSFER pin %d --> %d %d\n\n", pin, (uint8_t)value, retValue);
    }
    else if (retValue == PK_ERR_GENERIC) {
        printf("----> PK_ERR_GENERIC pin %d --> %d %d\n\n", pin, (uint8_t)value, retValue);
    }
    else if (retValue == PK_ERR_PARAMETER) {
        printf("----> PK_ERR_PARAMETER pin %d --> %d %d\n\n", pin, (uint8_t)value, retValue);
    }

    return retValue;
}

uint32_t PokeyDevice::outputPin(uint8_t pin)
{
    _pokey->Pins[--pin].PinFunction = PK_PinCap_digitalOutput;
    return PK_PinConfigurationSet(_pokey);
}

uint32_t PokeyDevice::inputPin(uint8_t pin)
{
    _pokey->Pins[--pin].PinFunction = PK_PinCap_digitalInput;
    return PK_PinConfigurationSet(_pokey);
}

int32_t PokeyDevice::name(std::string name)
{
    char *temp = (char *)std::calloc(1, 30);
    std::memcpy(_pokey->DeviceData.DeviceName, name.c_str(), 30);
    return PK_DeviceNameSet(_pokey);
}

int PokeyDevice::pinFromName(std::string targetName)
{
    std::map<std::string, int>::iterator it;
    it = _pinMap.find(targetName);

    if (it != _pinMap.end()) {
        return it->second;
    }
    else
        return -1;
}

void PokeyDevice::mapNameToPin(std::string name, int pin)
{
    _pinMap.emplace(name, pin);
}
<|endoftext|>


<commit_before>/*
 * File:   BackpropeagationLearner.cpp
 * Author: janvojt
 *
 * Created on July 13, 2014, 12:10 AM
 */

#include "BackpropagationLearner.h"

#include <cstring>
#include <string>
#include <stdexcept>
#include <limits>

#include "../log/LoggerFactory.h"
#include "log4cpp/Category.hh"

const int MAX_IMPROVEMENT_EPOCHS = 1000;

BackpropagationLearner::BackpropagationLearner(Network *network) {
    this->network = network;
    learningRate = 1;
    epochCounter = 0;
    epochLimit = 1000000;
    targetMse = .0001;
    errorTotal = std::numeric_limits<double>::infinity();
    useBias = network->getConfiguration()->getBias();
    noLayers = network->getConfiguration()->getLayers();
    deltaError = 0;
    improveEpochs = 0;
}

BackpropagationLearner::BackpropagationLearner(const BackpropagationLearner &orig) {
}

BackpropagationLearner::~BackpropagationLearner() {
    if (errorComputer != NULL) delete errorComputer;
    if (improveEpochs > 0) delete[] errorCache;
}

void BackpropagationLearner::train(LabeledDataset *trainingSet, LabeledDataset *validationSet) {
    double mse = std::numeric_limits<double>::infinity();
    double prevMse;
    LOG()->info("Started training with limits of %d epochs and target MSE of %f.", epochLimit, targetMse);
    do {
        epochCounter++;
        LOG()->debug("Starting epoch %d.", epochCounter);

        trainingSet->reset();
        int datasetSize = 0;
        prevMse = mse;
        mse = 0;
        while (trainingSet->hasNext()) {
            datasetSize++;
            double *pattern = trainingSet->next();
            double *expOutput = pattern + trainingSet->getInputDimension();

            LOG()->debug("Starting forward phase for dataset %d in epoch %d.", datasetSize, epochCounter);
            doForwardPhase(pattern);

            LOG()->debug("Starting backward phase for dataset %d in epoch %d.", datasetSize, epochCounter);
            doBackwardPhase(expOutput);

            mse += errorComputer->compute(network, expOutput);
        }
        mse = mse / datasetSize;
        LOG()->info("Finished epoch %d with MSE: %f.", epochCounter, mse);

        // calculate error on validation dataset
        validationSet->reset();
        if (validationSet->hasNext()) {
            mse = computeError(validationSet);
            LOG()->info("Computed MSE of %f on validation dataset.", mse);
        }

        // check criteria for stopping learning
        if (mse <= targetMse) {
            LOG()->info("Training successful after %d epochs with MSE of %f.", epochCounter, mse);
            break;
        } else if (!isErrorImprovement(mse, epochCounter)) {
            LOG()->info("Training interrupted after %d epochs with MSE of %f, because MSE improvement in last %d epochs was less than %f.", epochCounter, mse, improveEpochs, deltaError);
            break;
        } else if (epochCounter >= epochLimit) {
            LOG()->info("Training interrupted after %d epochs with MSE of %f.", epochCounter, mse);
            break;
        }

    } while (true); // stopping checks are at the end of the loop

}

void BackpropagationLearner::doForwardPhase(double *input) {
    network->setInput(input);
    network->run();
}

void BackpropagationLearner::doBackwardPhase(double *expectedOutput) {
    computeOutputGradients(expectedOutput);
    computeWeightDifferentials();
    adjustWeights();
    if (network->getConfiguration()->getBias()) {
        adjustBias();
    }
}

void BackpropagationLearner::validate(LabeledDataset *dataset) {
    if (dataset->getInputDimension() != network->getInputNeurons()) {
        throw new std::invalid_argument("Provided dataset must have the same input dimension as the number of input neurons!");
    }
    if (dataset->getOutputDimension() != network->getOutputNeurons()) {
        throw new std::invalid_argument("Provided dataset must have the same output dimension as the number of output neurons!");
    }
}

bool BackpropagationLearner::isErrorImprovement(double error, int epoch) {
    if (improveEpochs <= 0) {
        return true;
    }

    if (epoch > improveEpochs) {
        if ((errorCache[errorCachePtr] - deltaError) < error) {
            return false;
        }
    }

    errorCache[errorCachePtr] = error;
    errorCachePtr = (errorCachePtr+1) % improveEpochs;

    return true;
}

double BackpropagationLearner::computeError(LabeledDataset* ds) {
    int datasetSize = 0;
    double vMse = 0;
    while (ds->hasNext()) {
        datasetSize++;
        double *pattern = ds->next();
        double *expOutput = pattern + ds->getInputDimension();
        vMse += errorComputer->compute(network, expOutput);
    }

    return vMse / datasetSize;
}

void BackpropagationLearner::setImproveEpochs(int improveEpochs) {
    if (improveEpochs > MAX_IMPROVEMENT_EPOCHS) {
        LOG()->warn("Allowed maximum for error improvement epochs is %d, however %d was  requested. Going with %d.", MAX_IMPROVEMENT_EPOCHS, improveEpochs, MAX_IMPROVEMENT_EPOCHS);
        improveEpochs = MAX_IMPROVEMENT_EPOCHS;
    }

    if (this->improveEpochs > 0) {
        delete[] errorCache;
    }

    if (improveEpochs > 0) {
        errorCache = new double[improveEpochs];
        errorCachePtr = 0;
    }

    this->improveEpochs = improveEpochs;
}

void BackpropagationLearner::setEpochLimit(long limit) {
    epochLimit = limit;
}

void BackpropagationLearner::setErrorComputer(ErrorComputer* errorComputer) {
    this->errorComputer = errorComputer;
}

void BackpropagationLearner::setTargetMse(double mse) {
    targetMse = mse;
}

void BackpropagationLearner::setLearningRate(double learningRate) {
    this->learningRate = learningRate;
}

void BackpropagationLearner::setDeltaError(double deltaError) {
    this->deltaError = deltaError;
}
<commit_msg>Removed unused variable.<commit_after>/*
 * File:   BackpropeagationLearner.cpp
 * Author: janvojt
 *
 * Created on July 13, 2014, 12:10 AM
 */

#include "BackpropagationLearner.h"

#include <cstring>
#include <string>
#include <stdexcept>
#include <limits>

#include "../log/LoggerFactory.h"
#include "log4cpp/Category.hh"

const int MAX_IMPROVEMENT_EPOCHS = 1000;

BackpropagationLearner::BackpropagationLearner(Network *network) {
    this->network = network;
    learningRate = 1;
    epochCounter = 0;
    epochLimit = 1000000;
    targetMse = .0001;
    errorTotal = std::numeric_limits<double>::infinity();
    useBias = network->getConfiguration()->getBias();
    noLayers = network->getConfiguration()->getLayers();
    deltaError = 0;
    improveEpochs = 0;
}

BackpropagationLearner::BackpropagationLearner(const BackpropagationLearner &orig) {
}

BackpropagationLearner::~BackpropagationLearner() {
    if (errorComputer != NULL) delete errorComputer;
    if (improveEpochs > 0) delete[] errorCache;
}

void BackpropagationLearner::train(LabeledDataset *trainingSet, LabeledDataset *validationSet) {
    double mse = std::numeric_limits<double>::infinity();
    LOG()->info("Started training with limits of %d epochs and target MSE of %f.", epochLimit, targetMse);
    do {
        epochCounter++;
        LOG()->debug("Starting epoch %d.", epochCounter);

        trainingSet->reset();
        int datasetSize = 0;
        mse = 0;
        while (trainingSet->hasNext()) {
            datasetSize++;
            double *pattern = trainingSet->next();
            double *expOutput = pattern + trainingSet->getInputDimension();

            LOG()->debug("Starting forward phase for dataset %d in epoch %d.", datasetSize, epochCounter);
            doForwardPhase(pattern);

            LOG()->debug("Starting backward phase for dataset %d in epoch %d.", datasetSize, epochCounter);
            doBackwardPhase(expOutput);

            mse += errorComputer->compute(network, expOutput);
        }
        mse = mse / datasetSize;
        LOG()->info("Finished epoch %d with MSE: %f.", epochCounter, mse);

        // calculate error on validation dataset
        validationSet->reset();
        if (validationSet->hasNext()) {
            mse = computeError(validationSet);
            LOG()->info("Computed MSE of %f on validation dataset.", mse);
        }

        // check criteria for stopping learning
        if (mse <= targetMse) {
            LOG()->info("Training successful after %d epochs with MSE of %f.", epochCounter, mse);
            break;
        } else if (!isErrorImprovement(mse, epochCounter)) {
            LOG()->info("Training interrupted after %d epochs with MSE of %f, because MSE improvement in last %d epochs was less than %f.", epochCounter, mse, improveEpochs, deltaError);
            break;
        } else if (epochCounter >= epochLimit) {
            LOG()->info("Training interrupted after %d epochs with MSE of %f.", epochCounter, mse);
            break;
        }

    } while (true); // stopping checks are at the end of the loop

}

void BackpropagationLearner::doForwardPhase(double *input) {
    network->setInput(input);
    network->run();
}

void BackpropagationLearner::doBackwardPhase(double *expectedOutput) {
    computeOutputGradients(expectedOutput);
    computeWeightDifferentials();
    adjustWeights();
    if (network->getConfiguration()->getBias()) {
        adjustBias();
    }
}

void BackpropagationLearner::validate(LabeledDataset *dataset) {
    if (dataset->getInputDimension() != network->getInputNeurons()) {
        throw new std::invalid_argument("Provided dataset must have the same input dimension as the number of input neurons!");
    }
    if (dataset->getOutputDimension() != network->getOutputNeurons()) {
        throw new std::invalid_argument("Provided dataset must have the same output dimension as the number of output neurons!");
    }
}

bool BackpropagationLearner::isErrorImprovement(double error, int epoch) {
    if (improveEpochs <= 0) {
        return true;
    }

    if (epoch > improveEpochs) {
        if ((errorCache[errorCachePtr] - deltaError) < error) {
            return false;
        }
    }

    errorCache[errorCachePtr] = error;
    errorCachePtr = (errorCachePtr+1) % improveEpochs;

    return true;
}

double BackpropagationLearner::computeError(LabeledDataset* ds) {
    int datasetSize = 0;
    double vMse = 0;
    while (ds->hasNext()) {
        datasetSize++;
        double *pattern = ds->next();
        double *expOutput = pattern + ds->getInputDimension();
        vMse += errorComputer->compute(network, expOutput);
    }

    return vMse / datasetSize;
}

void BackpropagationLearner::setImproveEpochs(int improveEpochs) {
    if (improveEpochs > MAX_IMPROVEMENT_EPOCHS) {
        LOG()->warn("Allowed maximum for error improvement epochs is %d, however %d was  requested. Going with %d.", MAX_IMPROVEMENT_EPOCHS, improveEpochs, MAX_IMPROVEMENT_EPOCHS);
        improveEpochs = MAX_IMPROVEMENT_EPOCHS;
    }

    if (this->improveEpochs > 0) {
        delete[] errorCache;
    }

    if (improveEpochs > 0) {
        errorCache = new double[improveEpochs];
        errorCachePtr = 0;
    }

    this->improveEpochs = improveEpochs;
}

void BackpropagationLearner::setEpochLimit(long limit) {
    epochLimit = limit;
}

void BackpropagationLearner::setErrorComputer(ErrorComputer* errorComputer) {
    this->errorComputer = errorComputer;
}

void BackpropagationLearner::setTargetMse(double mse) {
    targetMse = mse;
}

void BackpropagationLearner::setLearningRate(double learningRate) {
    this->learningRate = learningRate;
}

void BackpropagationLearner::setDeltaError(double deltaError) {
    this->deltaError = deltaError;
}
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (C) 2015 Mark Charlebois. All rights reserved.
 *   Author: @author Mark Charlebois <charlebm#gmail.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file px4_posix_tasks.c
 * Implementation of existing task API for Linux
 */

#include "px4_log.h"
#include "px4_posix.h"
#include "px4_workqueue.h"
#include "hrt_work.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <stdbool.h>

#if !defined(__PX4_QURT)
#include <signal.h>
#endif

#include <fcntl.h>
#include <sched.h>
#include <unistd.h>
#include <string.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <string>

#include <px4_tasks.h>

#define MAX_CMD_LEN 100

#define PX4_MAX_TASKS 50
#define SHELL_TASK_ID (PX4_MAX_TASKS+1)

pthread_t _shell_task_id = 0;

struct task_entry {
	pthread_t pid;
	std::string name;
	bool isused;
	task_entry() : isused(false) {}
};

static task_entry taskmap[PX4_MAX_TASKS];

typedef struct {
	px4_main_t entry;
	int argc;
	char *argv[];
	// strings are allocated after the
} pthdata_t;

static void *entry_adapter(void *ptr)
{
	pthdata_t *data;
	data = (pthdata_t *) ptr;

	data->entry(data->argc, data->argv);
	PX4_WARN("Before waiting infinte busy loop");
	//for( ;; )
	//{
	//   volatile int x = 0;
	//   ++x;
	// }
	free(ptr);
	px4_task_exit(0);

	return NULL;
}

void
px4_systemreset(bool to_bootloader)
{
	PX4_WARN("Called px4_system_reset but NOT yet implemented.");
}

px4_task_t px4_task_spawn_cmd(const char *name, int scheduler, int priority, int stack_size, px4_main_t entry,
			      char *const argv[])
{
	struct sched_param param;
	pthread_attr_t attr;
	pthread_t task;
	int rv;
	int argc = 0;
	int i;
	unsigned int len = 0;
	unsigned long offset;
	unsigned long structsize;
	char *p = (char *)argv;

	PX4_DEBUG("Creating %s\n", name);
	PX4_DEBUG("attr address: 0x%X, param address: 0x%X", &attr, &param);

	// Calculate argc
	while (p != (char *)0) {
		p = argv[argc];

		if (p == (char *)0) {
			break;
		}

		++argc;
		len += strlen(p) + 1;
	}

	structsize = sizeof(pthdata_t) + (argc + 1) * sizeof(char *);
	pthdata_t *taskdata = nullptr;

	// not safe to pass stack data to the thread creation
	taskdata = (pthdata_t *)malloc(structsize + len);
	offset = ((unsigned long)taskdata) + structsize;

	taskdata->entry = entry;
	taskdata->argc = argc;

	for (i = 0; i < argc; i++) {
		PX4_DEBUG("arg %d %s\n", i, argv[i]);
		taskdata->argv[i] = (char *)offset;
		strcpy((char *)offset, argv[i]);
		offset += strlen(argv[i]) + 1;
	}

	// Must add NULL at end of argv
	taskdata->argv[argc] = (char *)0;

	rv = pthread_attr_init(&attr);

	if (rv != 0) {
		PX4_WARN("px4_task_spawn_cmd: failed to init thread attrs");
		return (rv < 0) ? rv : -rv;
	}

	PX4_DEBUG("stack address after pthread_attr_init: 0x%X", attr.stackaddr);
	PX4_DEBUG("attr address: 0x%X, param address: 0x%X", &attr, &param);
	rv = pthread_attr_getschedparam(&attr, &param);
	PX4_DEBUG("stack address after pthread_attr_getschedparam: 0x%X", attr.stackaddr);

	if (rv != 0) {
		PX4_WARN("px4_task_spawn_cmd: failed to get thread sched param");
		return (rv < 0) ? rv : -rv;
	}

#if 0
	rv = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);

	if (rv != 0) {
		PX4_WARN("px4_task_spawn_cmd: failed to set inherit sched");
		return (rv < 0) ? rv : -rv;
	}

	rv = pthread_attr_setschedpolicy(&attr, scheduler);

	if (rv != 0) {
		PX4_WARN("px4_task_spawn_cmd: failed to set sched policy");
		return (rv < 0) ? rv : -rv;
	}

#endif
	size_t fixed_stacksize = -1;
	pthread_attr_getstacksize(&attr, &fixed_stacksize);
	PX4_INFO("stack size: %d passed stacksize(%d)", fixed_stacksize, stack_size);
	fixed_stacksize = 8 * 1024;
	fixed_stacksize = (fixed_stacksize < (size_t)stack_size) ? (size_t)stack_size : fixed_stacksize;

	PX4_INFO("setting the thread[%s] stack size to[%d]", name, fixed_stacksize);
	pthread_attr_setstacksize(&attr, fixed_stacksize);

	PX4_DEBUG("stack address after pthread_attr_setstacksize: 0x%X", attr.stackaddr);
	param.sched_priority = priority;

	rv = pthread_attr_setschedparam(&attr, &param);

	if (rv != 0) {
		PX4_ERR("px4_task_spawn_cmd: failed to set sched param");
		return (rv < 0) ? rv : -rv;
	}

	rv = pthread_create(&task, &attr, &entry_adapter, (void *) taskdata);

	if (rv != 0) {
		PX4_ERR("px4_task_spawn_cmd: pthread_create failed, error: %d", rv);
		return (rv < 0) ? rv : -rv;
	}

	for (i = 0; i < PX4_MAX_TASKS; ++i) {
		if (taskmap[i].isused == false) {
			taskmap[i].pid = task;
			taskmap[i].name = name;
			taskmap[i].isused = true;
			break;
		}
	}

	if (i >= PX4_MAX_TASKS) {
		return -ENOSPC;
	}

	return i;
}

int px4_task_delete(px4_task_t id)
{
	int rv = 0;
	pthread_t pid;
	PX4_WARN("Called px4_task_delete");

	if (id < PX4_MAX_TASKS && taskmap[id].isused) {
		pid = taskmap[id].pid;

	} else {
		return -EINVAL;
	}

	// If current thread then exit, otherwise cancel
	if (pthread_self() == pid) {
		taskmap[id].isused = false;
		pthread_exit(0);

	} else {
		rv = pthread_cancel(pid);
	}

	taskmap[id].isused = false;

	return rv;
}

void px4_task_exit(int ret)
{
	int i;
	pthread_t pid = pthread_self();

	// Get pthread ID from the opaque ID
	for (i = 0; i < PX4_MAX_TASKS; ++i) {
		if (taskmap[i].pid == pid) {
			taskmap[i].isused = false;
			break;
		}
	}

	if (i >= PX4_MAX_TASKS)  {
		PX4_ERR("px4_task_exit: self task not found!");

	} else {
		PX4_DEBUG("px4_task_exit: %s", taskmap[i].name.c_str());
	}

	//pthread_exit((void *)(unsigned long)ret);
}

int px4_task_kill(px4_task_t id, int sig)
{
	int rv = 0;
	pthread_t pid;
	PX4_DEBUG("Called px4_task_kill %d, taskname %s", sig, taskmap[id].name.c_str());

	if (id < PX4_MAX_TASKS && taskmap[id].pid != 0) {
		pid = taskmap[id].pid;

	} else {
		return -EINVAL;
	}

	// If current thread then exit, otherwise cancel
	rv = pthread_kill(pid, sig);

	return rv;
}

void px4_show_tasks()
{
	int idx;
	int count = 0;

	PX4_INFO("Active Tasks:");

	for (idx = 0; idx < PX4_MAX_TASKS; idx++) {
		if (taskmap[idx].isused) {
			PX4_INFO("   %-10s %d", taskmap[idx].name.c_str(), taskmap[idx].pid);
			count++;
		}
	}

	if (count == 0) {
		PX4_INFO("   No running tasks");
	}

}

__BEGIN_DECLS

unsigned long px4_getpid()
{
	pthread_t pid = pthread_self();
//
//	if (pid == _shell_task_id)
//		return SHELL_TASK_ID;

	// Get pthread ID from the opaque ID
	for (int i = 0; i < PX4_MAX_TASKS; ++i) {
		if (taskmap[i].isused && taskmap[i].pid == pid) {
			return i;
		}
	}

	PX4_ERR("px4_getpid() called from unknown thread context!");
	return ~0;
}

const char *getprogname();
const char *getprogname()
{
	pthread_t pid = pthread_self();

	for (int i = 0; i < PX4_MAX_TASKS; i++) {
		if (taskmap[i].isused && taskmap[i].pid == pid) {
			return taskmap[i].name.c_str();
		}
	}

	return "Unknown App";
}

static void timer_cb(void *data)
{
	px4_sem_t *sem = reinterpret_cast<px4_sem_t *>(data);

	sem_post(sem);
}

int px4_sem_timedwait(px4_sem_t *sem, const struct timespec *ts)
{
	work_s _hpwork = {};

	// Create a timer to unblock
	uint32_t timeout = ts->tv_sec * 1000000 + (ts->tv_nsec / 1000);
	hrt_work_queue(&_hpwork, (worker_t)&timer_cb, (void *)sem, timeout);
	sem_wait(sem);
	hrt_work_cancel(&_hpwork);
	return 0;
}

int px4_prctl(int option, const char *arg2, unsigned pid)
{
	int rv;

	switch (option) {
	case PR_SET_NAME:
		// set the threads name - Not supported
		// rv = pthread_setname_np(pthread_self(), arg2);
		rv = -1;
		break;

	default:
		rv = -1;
		PX4_WARN("FAILED SETTING TASK NAME");
		break;
	}

	return rv;
}
__END_DECLS
<commit_msg>px4_qurt_tasks: fix header<commit_after>/****************************************************************************
 *
 *   Copyright (C) 2015-2016 Mark Charlebois. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 3. Neither the name PX4 nor the names of its contributors may be
 *    used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 ****************************************************************************/

/**
 * @file px4_qurt_tasks.c
 * Implementation of existing task API for QURT.
 *
 * @author Mark Charlebois <charlebm@gmail.com>
 */

#include "px4_log.h"
#include "px4_posix.h"
#include "px4_workqueue.h"
#include "hrt_work.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <stdbool.h>

#if !defined(__PX4_QURT)
#include <signal.h>
#endif

#include <fcntl.h>
#include <sched.h>
#include <unistd.h>
#include <string.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <string>

#include <px4_tasks.h>

#define MAX_CMD_LEN 100

#define PX4_MAX_TASKS 50
#define SHELL_TASK_ID (PX4_MAX_TASKS+1)

pthread_t _shell_task_id = 0;

struct task_entry {
	pthread_t pid;
	std::string name;
	bool isused;
	task_entry() : isused(false) {}
};

static task_entry taskmap[PX4_MAX_TASKS];

typedef struct {
	px4_main_t entry;
	int argc;
	char *argv[];
	// strings are allocated after the
} pthdata_t;

static void *entry_adapter(void *ptr)
{
	pthdata_t *data;
	data = (pthdata_t *) ptr;

	data->entry(data->argc, data->argv);
	PX4_WARN("Before waiting infinte busy loop");
	//for( ;; )
	//{
	//   volatile int x = 0;
	//   ++x;
	// }
	free(ptr);
	px4_task_exit(0);

	return NULL;
}

void
px4_systemreset(bool to_bootloader)
{
	PX4_WARN("Called px4_system_reset but NOT yet implemented.");
}

px4_task_t px4_task_spawn_cmd(const char *name, int scheduler, int priority, int stack_size, px4_main_t entry,
			      char *const argv[])
{
	struct sched_param param;
	pthread_attr_t attr;
	pthread_t task;
	int rv;
	int argc = 0;
	int i;
	unsigned int len = 0;
	unsigned long offset;
	unsigned long structsize;
	char *p = (char *)argv;

	PX4_DEBUG("Creating %s\n", name);
	PX4_DEBUG("attr address: 0x%X, param address: 0x%X", &attr, &param);

	// Calculate argc
	while (p != (char *)0) {
		p = argv[argc];

		if (p == (char *)0) {
			break;
		}

		++argc;
		len += strlen(p) + 1;
	}

	structsize = sizeof(pthdata_t) + (argc + 1) * sizeof(char *);
	pthdata_t *taskdata = nullptr;

	// not safe to pass stack data to the thread creation
	taskdata = (pthdata_t *)malloc(structsize + len);
	offset = ((unsigned long)taskdata) + structsize;

	taskdata->entry = entry;
	taskdata->argc = argc;

	for (i = 0; i < argc; i++) {
		PX4_DEBUG("arg %d %s\n", i, argv[i]);
		taskdata->argv[i] = (char *)offset;
		strcpy((char *)offset, argv[i]);
		offset += strlen(argv[i]) + 1;
	}

	// Must add NULL at end of argv
	taskdata->argv[argc] = (char *)0;

	rv = pthread_attr_init(&attr);

	if (rv != 0) {
		PX4_WARN("px4_task_spawn_cmd: failed to init thread attrs");
		return (rv < 0) ? rv : -rv;
	}

	PX4_DEBUG("stack address after pthread_attr_init: 0x%X", attr.stackaddr);
	PX4_DEBUG("attr address: 0x%X, param address: 0x%X", &attr, &param);
	rv = pthread_attr_getschedparam(&attr, &param);
	PX4_DEBUG("stack address after pthread_attr_getschedparam: 0x%X", attr.stackaddr);

	if (rv != 0) {
		PX4_WARN("px4_task_spawn_cmd: failed to get thread sched param");
		return (rv < 0) ? rv : -rv;
	}

#if 0
	rv = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);

	if (rv != 0) {
		PX4_WARN("px4_task_spawn_cmd: failed to set inherit sched");
		return (rv < 0) ? rv : -rv;
	}

	rv = pthread_attr_setschedpolicy(&attr, scheduler);

	if (rv != 0) {
		PX4_WARN("px4_task_spawn_cmd: failed to set sched policy");
		return (rv < 0) ? rv : -rv;
	}

#endif
	size_t fixed_stacksize = -1;
	pthread_attr_getstacksize(&attr, &fixed_stacksize);
	PX4_INFO("stack size: %d passed stacksize(%d)", fixed_stacksize, stack_size);
	fixed_stacksize = 8 * 1024;
	fixed_stacksize = (fixed_stacksize < (size_t)stack_size) ? (size_t)stack_size : fixed_stacksize;

	PX4_INFO("setting the thread[%s] stack size to[%d]", name, fixed_stacksize);
	pthread_attr_setstacksize(&attr, fixed_stacksize);

	PX4_DEBUG("stack address after pthread_attr_setstacksize: 0x%X", attr.stackaddr);
	param.sched_priority = priority;

	rv = pthread_attr_setschedparam(&attr, &param);

	if (rv != 0) {
		PX4_ERR("px4_task_spawn_cmd: failed to set sched param");
		return (rv < 0) ? rv : -rv;
	}

	rv = pthread_create(&task, &attr, &entry_adapter, (void *) taskdata);

	if (rv != 0) {
		PX4_ERR("px4_task_spawn_cmd: pthread_create failed, error: %d", rv);
		return (rv < 0) ? rv : -rv;
	}

	for (i = 0; i < PX4_MAX_TASKS; ++i) {
		if (taskmap[i].isused == false) {
			taskmap[i].pid = task;
			taskmap[i].name = name;
			taskmap[i].isused = true;
			break;
		}
	}

	if (i >= PX4_MAX_TASKS) {
		return -ENOSPC;
	}

	return i;
}

int px4_task_delete(px4_task_t id)
{
	int rv = 0;
	pthread_t pid;
	PX4_WARN("Called px4_task_delete");

	if (id < PX4_MAX_TASKS && taskmap[id].isused) {
		pid = taskmap[id].pid;

	} else {
		return -EINVAL;
	}

	// If current thread then exit, otherwise cancel
	if (pthread_self() == pid) {
		taskmap[id].isused = false;
		pthread_exit(0);

	} else {
		rv = pthread_cancel(pid);
	}

	taskmap[id].isused = false;

	return rv;
}

void px4_task_exit(int ret)
{
	int i;
	pthread_t pid = pthread_self();

	// Get pthread ID from the opaque ID
	for (i = 0; i < PX4_MAX_TASKS; ++i) {
		if (taskmap[i].pid == pid) {
			taskmap[i].isused = false;
			break;
		}
	}

	if (i >= PX4_MAX_TASKS)  {
		PX4_ERR("px4_task_exit: self task not found!");

	} else {
		PX4_DEBUG("px4_task_exit: %s", taskmap[i].name.c_str());
	}

	//pthread_exit((void *)(unsigned long)ret);
}

int px4_task_kill(px4_task_t id, int sig)
{
	int rv = 0;
	pthread_t pid;
	PX4_DEBUG("Called px4_task_kill %d, taskname %s", sig, taskmap[id].name.c_str());

	if (id < PX4_MAX_TASKS && taskmap[id].pid != 0) {
		pid = taskmap[id].pid;

	} else {
		return -EINVAL;
	}

	// If current thread then exit, otherwise cancel
	rv = pthread_kill(pid, sig);

	return rv;
}

void px4_show_tasks()
{
	int idx;
	int count = 0;

	PX4_INFO("Active Tasks:");

	for (idx = 0; idx < PX4_MAX_TASKS; idx++) {
		if (taskmap[idx].isused) {
			PX4_INFO("   %-10s %d", taskmap[idx].name.c_str(), taskmap[idx].pid);
			count++;
		}
	}

	if (count == 0) {
		PX4_INFO("   No running tasks");
	}

}

__BEGIN_DECLS

unsigned long px4_getpid()
{
	pthread_t pid = pthread_self();
//
//	if (pid == _shell_task_id)
//		return SHELL_TASK_ID;

	// Get pthread ID from the opaque ID
	for (int i = 0; i < PX4_MAX_TASKS; ++i) {
		if (taskmap[i].isused && taskmap[i].pid == pid) {
			return i;
		}
	}

	PX4_ERR("px4_getpid() called from unknown thread context!");
	return ~0;
}

const char *getprogname();
const char *getprogname()
{
	pthread_t pid = pthread_self();

	for (int i = 0; i < PX4_MAX_TASKS; i++) {
		if (taskmap[i].isused && taskmap[i].pid == pid) {
			return taskmap[i].name.c_str();
		}
	}

	return "Unknown App";
}

static void timer_cb(void *data)
{
	px4_sem_t *sem = reinterpret_cast<px4_sem_t *>(data);

	sem_post(sem);
}

int px4_sem_timedwait(px4_sem_t *sem, const struct timespec *ts)
{
	work_s _hpwork = {};

	// Create a timer to unblock
	uint32_t timeout = ts->tv_sec * 1000000 + (ts->tv_nsec / 1000);
	hrt_work_queue(&_hpwork, (worker_t)&timer_cb, (void *)sem, timeout);
	sem_wait(sem);
	hrt_work_cancel(&_hpwork);
	return 0;
}

int px4_prctl(int option, const char *arg2, unsigned pid)
{
	int rv;

	switch (option) {
	case PR_SET_NAME:
		// set the threads name - Not supported
		// rv = pthread_setname_np(pthread_self(), arg2);
		rv = -1;
		break;

	default:
		rv = -1;
		PX4_WARN("FAILED SETTING TASK NAME");
		break;
	}

	return rv;
}
__END_DECLS
<|endoftext|>