<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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.
 *
 ***************************************************************/

/************************************************************************
**
**	Set up the various dprintf variables based on the configuration file.
**
************************************************************************/

#include "condor_common.h"
#include "condor_debug.h"
#include "condor_string.h"
#include "condor_sys_types.h"

#if HAVE_BACKTRACE
#include "sig_install.h"
#endif

int		Termlog = 0;

extern int		DebugFlags;
extern FILE		*DebugFP;
extern uint64_t		MaxLog[D_NUMLEVELS+1];
extern int 			MaxLogNum[D_NUMLEVELS+1];
extern char		*DebugFile[D_NUMLEVELS+1];
extern char		*DebugLock;
extern char		*_condor_DebugFlagNames[];
extern int		_condor_dprintf_works;
extern time_t	DebugLastMod;
extern int		DebugUseTimestamps;
extern int      DebugContinueOnOpenFailure;

extern void		_condor_set_debug_flags( const char *strflags );
extern void		_condor_dprintf_saved_lines( void );

FILE *open_debug_file( int debug_level, char flags[] );

#if HAVE_EXT_GCB
void	_condor_gcb_dprintf_va( int flags, char* fmt, va_list args );
extern "C" void Generic_set_log_va(void(*app_log_va)(int level, char *fmt, va_list args));
#endif

#if HAVE_BACKTRACE
static void
sig_backtrace_handler(int signum)
{
	dprintf_dump_stack();

		// terminate for the same reason.
	struct sigaction sa;
	sa.sa_handler = SIG_DFL;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	sigaction(signum, &sa, NULL);
	sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL);

	raise(signum);
}

static void
install_backtrace_handler(void)
{
	sigset_t fullset;
	sigfillset( &fullset );
	install_sig_handler_with_mask(SIGSEGV, &fullset, sig_backtrace_handler);
	install_sig_handler_with_mask(SIGABRT, &fullset, sig_backtrace_handler);
	install_sig_handler_with_mask(SIGILL, &fullset, sig_backtrace_handler);
	install_sig_handler_with_mask(SIGFPE, &fullset, sig_backtrace_handler);
	install_sig_handler_with_mask(SIGBUS, &fullset, sig_backtrace_handler);
}
#endif

int
dprintf_config_ContinueOnFailure ( int fContinue )
{
    int fOld = DebugContinueOnOpenFailure;
	DebugContinueOnOpenFailure = fContinue;
	return fOld;
}

void
dprintf_config( const char *subsys )
{
	char pname[ BUFSIZ ];
	char *pval;
	static int first_time = 1;
	int want_truncate;
	int debug_level;

	/*
	**  We want to initialize this here so if we reconfig and the
	**	debug flags have changed, we actually use the new
	**  flags.  -Derek Wright 12/8/97
	*/
	DebugFlags = D_ALWAYS;

	/*
	** First, add the debug flags that are shared by everyone.
	*/
	pval = param("ALL_DEBUG");
	if( pval ) {
		_condor_set_debug_flags( pval );
		free( pval );
	}

	/*
	**  Then, pick up the subsys_DEBUG parameters.   Note: if we don't have
	**  anything set, we just leave it as D_ALWAYS.
	*/
	(void)sprintf(pname, "%s_DEBUG", subsys);
	pval = param(pname);
	if( pval ) {
		_condor_set_debug_flags( pval );
		free( pval );
	}

#ifdef WIN32
		/* Two reasons why we need to lock the log in Windows
		 * (when a lock is configured)
		 * 1) File rotation requires exclusive access in Windows.
		 * 2) O_APPEND doesn't guarantee atomic writes in Windows
		 */
	DebugShouldLockToAppend = 1;
#else
	DebugShouldLockToAppend = param_boolean_int("LOCK_DEBUG_LOG_TO_APPEND",0);
#endif

	/*
	**	If this is not going to the terminal, pick up the name
	**	of the log file, maximum log size, and the name of the
	**	lock file (if it is specified).
	*/
	if( !( Termlog) ) {
		for (debug_level = 0; debug_level <= D_NUMLEVELS; debug_level++) {
			want_truncate = 0;
			if (debug_level == 0) {
				/*
				** the level 0 file gets all debug messages; thus, the
				** offset into DebugFlagNames is off by one, since the
				** first level-specific file goes into the other arrays at
				** index 1
				*/
				(void)sprintf(pname, "%s_LOG", subsys);
			} else {
				(void)sprintf(pname, "%s_%s_LOG", subsys,
							  _condor_DebugFlagNames[debug_level-1]+2);
			}

			// Hold a temporary copy of the old file pointer until
			// *after* the param -- param can dprintf() in some cases
			{
				char	*tmp = DebugFile[debug_level];

				// NEGOTIATOR_MATCH_LOG is necessary by default, but debug_level
				// is not 0
				if(debug_level == 0)
				{
					char	*tmp2 = param(pname);

					// No default value found, so use $(LOG)/$(SUBSYSTEM)Log
					if(!tmp2) {
						// This char* will never be freed, but as long as
						// defaults are defined in condor_c++_util/param_info.in
						// we will never get here.
						char *str;
						char *log = param("LOG");
						char *subsys = param("SUBSYSTEM");
						if(!log || !subsys) {
							EXCEPT("Unable to find LOG or SUBSYSTEM.\n");
						}

						str = (char*)malloc(strlen(log) + strlen(subsys) + 5);
						sprintf(str, "%s%c%sLog", log, DIR_DELIM_CHAR, subsys);

						DebugFile[debug_level] = str;

						free(log);
						free(subsys);
					}
					else {
						DebugFile[debug_level] = tmp2;
					}
				}
				else {
					// This is looking up configuration options that I can't
					// find documentation for, so intead of coding in an
					// incorrect default value, I'm gonna use
					// param_without_default.
					// tristan 5/29/09
					DebugFile[debug_level] = param_without_default(pname);
				}
				if ( tmp ) {
					free( tmp );
				}
			}

			if( debug_level == 0 && DebugFile[0] == NULL ) {
				EXCEPT("No '%s' parameter specified.", pname);
			} else if ( DebugFile[debug_level] != NULL ) {

				if (debug_level == 0 && first_time) {
					struct stat stat_buf;
					if ( stat( DebugFile[debug_level], &stat_buf ) >= 0 ) {
						DebugLastMod = stat_buf.st_mtime > stat_buf.st_ctime ? stat_buf.st_mtime : stat_buf.st_ctime;
					} else {
						DebugLastMod = -errno;
					}
				}

				if (debug_level == 0) {
					(void)sprintf(pname, "TRUNC_%s_LOG_ON_OPEN", subsys);
				} else {
					(void)sprintf(pname, "TRUNC_%s_%s_LOG_ON_OPEN", subsys,
								  _condor_DebugFlagNames[debug_level-1]+2);
				}
				pval = param(pname);
				if( pval ) {
					if( *pval == 't' || *pval == 'T' ) {
						want_truncate = 1;
					}
					free(pval);
				}

				if (debug_level == 0) {
					(void)sprintf(pname, "%s_LOCK", subsys);
					if (DebugLock) {
						free(DebugLock);
					}
					DebugLock = param(pname);
				}

				if( first_time && want_truncate ) {
					DebugFP = debug_lock(debug_level, "w", 0);
				} else {
					DebugFP = debug_lock(debug_level, "a", 0);
				}

				if( DebugFP == NULL && debug_level == 0 ) {
                   #ifdef WIN32
					/*
					** If we could not open the log file, we might want to keep running anyway.
					** If we do, then set the log filename to NUL so we don't keep trying
					** (and failing) to open the file.
					*/
					if (DebugContinueOnOpenFailure) {

						// change the debug file to point to the NUL device.
						static const char strDevNull[] = "NUL";//"\\\\.\\Device\\Null";
						char * psz = (char*)malloc(sizeof(strDevNull));
						strcpy(psz, strDevNull);
						if (DebugFile[debug_level])
							free(DebugFile[debug_level]);
						DebugFile[debug_level] = psz;

					} else
                   #endif
					{
					    EXCEPT("Cannot open log file '%s'",
						       DebugFile[debug_level]);
					}
				}

				if (DebugFP) (void)debug_unlock( debug_level );
				DebugFP = (FILE *)0;

				if (debug_level == 0) {
					(void)sprintf(pname, "MAX_%s_LOG", subsys);
				} else {
					(void)sprintf(pname, "MAX_%s_%s_LOG", subsys,
								  _condor_DebugFlagNames[debug_level-1]+2);
				}
				pval = param(pname);
				if( pval != NULL ) {
					MaxLog[debug_level] = atoi( pval );
					free(pval);
				} else {
					MaxLog[debug_level] = 1024*1024;
				}

				if (debug_level == 0) {
					(void)sprintf(pname, "MAX_NUM_%s_LOG", subsys);
				} else {
					(void)sprintf(pname, "MAX_NUM_%s_%s_LOG", subsys,
								  _condor_DebugFlagNames[debug_level-1]+2);
				}
				pval = param(pname);
				if (pval != NULL) {
					MaxLogNum[debug_level] = atoi(pval);
					free(pval);
				} else {
					MaxLogNum[debug_level] = 1;
				}
			}
		}
	} else {

#if !defined(WIN32)
		setlinebuf( stderr );
#endif

		(void)fflush( stderr );	/* Don't know why we need this, but if not here
							   the first couple dprintf don't come out right */
	}

	first_time = 0;
	_condor_dprintf_works = 1;
#if HAVE_EXT_GCB
		/*
		  this method currently only lives in libGCB.a, so don't even
		  try to param() or call this function unless we're on a
		  platform where we're using the GCB external
		*/
    if ( param_boolean_int("NET_REMAP_ENABLE", 0) ) {
        Generic_set_log_va(_condor_gcb_dprintf_va);
    }
#endif

		/*
		  If LOGS_USE_TIMESTAMP is enabled, we will print out Unix timestamps
		  instead of the standard date format in all the log messages
		*/
	DebugUseTimestamps = param_boolean_int( "LOGS_USE_TIMESTAMP", FALSE );

#if HAVE_BACKTRACE
	install_backtrace_handler();
#endif

	_condor_dprintf_saved_lines();
}

#if HAVE_EXT_GCB
void
_condor_gcb_dprintf_va( int flags, char* fmt, va_list args )
{
	char* new_fmt;
	int len;

	len = strlen(fmt);
	new_fmt = (char*) malloc( (len + 6) * sizeof(char) );
	if( ! new_fmt ) {
		EXCEPT( "_condor_gcb_dprintf_va() out of memory!" );
	}
	snprintf( new_fmt, len + 6, "GCB: %s", fmt );
	_condor_dprintf_va( flags, new_fmt, args );
	free( new_fmt );
}
#endif /* HAVE_EXT_GCB */
<commit_msg>Fixed _condor_DebugFlagNames const commit, missed a file<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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.
 *
 ***************************************************************/

/************************************************************************
**
**	Set up the various dprintf variables based on the configuration file.
**
************************************************************************/

#include "condor_common.h"
#include "condor_debug.h"
#include "condor_string.h"
#include "condor_sys_types.h"

#if HAVE_BACKTRACE
#include "sig_install.h"
#endif

int		Termlog = 0;

extern int		DebugFlags;
extern FILE		*DebugFP;
extern uint64_t		MaxLog[D_NUMLEVELS+1];
extern int 			MaxLogNum[D_NUMLEVELS+1];
extern char		*DebugFile[D_NUMLEVELS+1];
extern char		*DebugLock;
extern const char		*_condor_DebugFlagNames[];
extern int		_condor_dprintf_works;
extern time_t	DebugLastMod;
extern int		DebugUseTimestamps;
extern int      DebugContinueOnOpenFailure;

extern void		_condor_set_debug_flags( const char *strflags );
extern void		_condor_dprintf_saved_lines( void );

FILE *open_debug_file( int debug_level, char flags[] );

#if HAVE_EXT_GCB
void	_condor_gcb_dprintf_va( int flags, char* fmt, va_list args );
extern "C" void Generic_set_log_va(void(*app_log_va)(int level, char *fmt, va_list args));
#endif

#if HAVE_BACKTRACE
static void
sig_backtrace_handler(int signum)
{
	dprintf_dump_stack();

		// terminate for the same reason.
	struct sigaction sa;
	sa.sa_handler = SIG_DFL;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	sigaction(signum, &sa, NULL);
	sigprocmask(SIG_SETMASK, &sa.sa_mask, NULL);

	raise(signum);
}

static void
install_backtrace_handler(void)
{
	sigset_t fullset;
	sigfillset( &fullset );
	install_sig_handler_with_mask(SIGSEGV, &fullset, sig_backtrace_handler);
	install_sig_handler_with_mask(SIGABRT, &fullset, sig_backtrace_handler);
	install_sig_handler_with_mask(SIGILL, &fullset, sig_backtrace_handler);
	install_sig_handler_with_mask(SIGFPE, &fullset, sig_backtrace_handler);
	install_sig_handler_with_mask(SIGBUS, &fullset, sig_backtrace_handler);
}
#endif

int
dprintf_config_ContinueOnFailure ( int fContinue )
{
    int fOld = DebugContinueOnOpenFailure;
	DebugContinueOnOpenFailure = fContinue;
	return fOld;
}

void
dprintf_config( const char *subsys )
{
	char pname[ BUFSIZ ];
	char *pval;
	static int first_time = 1;
	int want_truncate;
	int debug_level;

	/*
	**  We want to initialize this here so if we reconfig and the
	**	debug flags have changed, we actually use the new
	**  flags.  -Derek Wright 12/8/97
	*/
	DebugFlags = D_ALWAYS;

	/*
	** First, add the debug flags that are shared by everyone.
	*/
	pval = param("ALL_DEBUG");
	if( pval ) {
		_condor_set_debug_flags( pval );
		free( pval );
	}

	/*
	**  Then, pick up the subsys_DEBUG parameters.   Note: if we don't have
	**  anything set, we just leave it as D_ALWAYS.
	*/
	(void)sprintf(pname, "%s_DEBUG", subsys);
	pval = param(pname);
	if( pval ) {
		_condor_set_debug_flags( pval );
		free( pval );
	}

#ifdef WIN32
		/* Two reasons why we need to lock the log in Windows
		 * (when a lock is configured)
		 * 1) File rotation requires exclusive access in Windows.
		 * 2) O_APPEND doesn't guarantee atomic writes in Windows
		 */
	DebugShouldLockToAppend = 1;
#else
	DebugShouldLockToAppend = param_boolean_int("LOCK_DEBUG_LOG_TO_APPEND",0);
#endif

	/*
	**	If this is not going to the terminal, pick up the name
	**	of the log file, maximum log size, and the name of the
	**	lock file (if it is specified).
	*/
	if( !( Termlog) ) {
		for (debug_level = 0; debug_level <= D_NUMLEVELS; debug_level++) {
			want_truncate = 0;
			if (debug_level == 0) {
				/*
				** the level 0 file gets all debug messages; thus, the
				** offset into DebugFlagNames is off by one, since the
				** first level-specific file goes into the other arrays at
				** index 1
				*/
				(void)sprintf(pname, "%s_LOG", subsys);
			} else {
				(void)sprintf(pname, "%s_%s_LOG", subsys,
							  _condor_DebugFlagNames[debug_level-1]+2);
			}

			// Hold a temporary copy of the old file pointer until
			// *after* the param -- param can dprintf() in some cases
			{
				char	*tmp = DebugFile[debug_level];

				// NEGOTIATOR_MATCH_LOG is necessary by default, but debug_level
				// is not 0
				if(debug_level == 0)
				{
					char	*tmp2 = param(pname);

					// No default value found, so use $(LOG)/$(SUBSYSTEM)Log
					if(!tmp2) {
						// This char* will never be freed, but as long as
						// defaults are defined in condor_c++_util/param_info.in
						// we will never get here.
						char *str;
						char *log = param("LOG");
						char *subsys = param("SUBSYSTEM");
						if(!log || !subsys) {
							EXCEPT("Unable to find LOG or SUBSYSTEM.\n");
						}

						str = (char*)malloc(strlen(log) + strlen(subsys) + 5);
						sprintf(str, "%s%c%sLog", log, DIR_DELIM_CHAR, subsys);

						DebugFile[debug_level] = str;

						free(log);
						free(subsys);
					}
					else {
						DebugFile[debug_level] = tmp2;
					}
				}
				else {
					// This is looking up configuration options that I can't
					// find documentation for, so intead of coding in an
					// incorrect default value, I'm gonna use
					// param_without_default.
					// tristan 5/29/09
					DebugFile[debug_level] = param_without_default(pname);
				}
				if ( tmp ) {
					free( tmp );
				}
			}

			if( debug_level == 0 && DebugFile[0] == NULL ) {
				EXCEPT("No '%s' parameter specified.", pname);
			} else if ( DebugFile[debug_level] != NULL ) {

				if (debug_level == 0 && first_time) {
					struct stat stat_buf;
					if ( stat( DebugFile[debug_level], &stat_buf ) >= 0 ) {
						DebugLastMod = stat_buf.st_mtime > stat_buf.st_ctime ? stat_buf.st_mtime : stat_buf.st_ctime;
					} else {
						DebugLastMod = -errno;
					}
				}

				if (debug_level == 0) {
					(void)sprintf(pname, "TRUNC_%s_LOG_ON_OPEN", subsys);
				} else {
					(void)sprintf(pname, "TRUNC_%s_%s_LOG_ON_OPEN", subsys,
								  _condor_DebugFlagNames[debug_level-1]+2);
				}
				pval = param(pname);
				if( pval ) {
					if( *pval == 't' || *pval == 'T' ) {
						want_truncate = 1;
					}
					free(pval);
				}

				if (debug_level == 0) {
					(void)sprintf(pname, "%s_LOCK", subsys);
					if (DebugLock) {
						free(DebugLock);
					}
					DebugLock = param(pname);
				}

				if( first_time && want_truncate ) {
					DebugFP = debug_lock(debug_level, "w", 0);
				} else {
					DebugFP = debug_lock(debug_level, "a", 0);
				}

				if( DebugFP == NULL && debug_level == 0 ) {
                   #ifdef WIN32
					/*
					** If we could not open the log file, we might want to keep running anyway.
					** If we do, then set the log filename to NUL so we don't keep trying
					** (and failing) to open the file.
					*/
					if (DebugContinueOnOpenFailure) {

						// change the debug file to point to the NUL device.
						static const char strDevNull[] = "NUL";//"\\\\.\\Device\\Null";
						char * psz = (char*)malloc(sizeof(strDevNull));
						strcpy(psz, strDevNull);
						if (DebugFile[debug_level])
							free(DebugFile[debug_level]);
						DebugFile[debug_level] = psz;

					} else
                   #endif
					{
					    EXCEPT("Cannot open log file '%s'",
						       DebugFile[debug_level]);
					}
				}

				if (DebugFP) (void)debug_unlock( debug_level );
				DebugFP = (FILE *)0;

				if (debug_level == 0) {
					(void)sprintf(pname, "MAX_%s_LOG", subsys);
				} else {
					(void)sprintf(pname, "MAX_%s_%s_LOG", subsys,
								  _condor_DebugFlagNames[debug_level-1]+2);
				}
				pval = param(pname);
				if( pval != NULL ) {
					MaxLog[debug_level] = atoi( pval );
					free(pval);
				} else {
					MaxLog[debug_level] = 1024*1024;
				}

				if (debug_level == 0) {
					(void)sprintf(pname, "MAX_NUM_%s_LOG", subsys);
				} else {
					(void)sprintf(pname, "MAX_NUM_%s_%s_LOG", subsys,
								  _condor_DebugFlagNames[debug_level-1]+2);
				}
				pval = param(pname);
				if (pval != NULL) {
					MaxLogNum[debug_level] = atoi(pval);
					free(pval);
				} else {
					MaxLogNum[debug_level] = 1;
				}
			}
		}
	} else {

#if !defined(WIN32)
		setlinebuf( stderr );
#endif

		(void)fflush( stderr );	/* Don't know why we need this, but if not here
							   the first couple dprintf don't come out right */
	}

	first_time = 0;
	_condor_dprintf_works = 1;
#if HAVE_EXT_GCB
		/*
		  this method currently only lives in libGCB.a, so don't even
		  try to param() or call this function unless we're on a
		  platform where we're using the GCB external
		*/
    if ( param_boolean_int("NET_REMAP_ENABLE", 0) ) {
        Generic_set_log_va(_condor_gcb_dprintf_va);
    }
#endif

		/*
		  If LOGS_USE_TIMESTAMP is enabled, we will print out Unix timestamps
		  instead of the standard date format in all the log messages
		*/
	DebugUseTimestamps = param_boolean_int( "LOGS_USE_TIMESTAMP", FALSE );

#if HAVE_BACKTRACE
	install_backtrace_handler();
#endif

	_condor_dprintf_saved_lines();
}

#if HAVE_EXT_GCB
void
_condor_gcb_dprintf_va( int flags, char* fmt, va_list args )
{
	char* new_fmt;
	int len;

	len = strlen(fmt);
	new_fmt = (char*) malloc( (len + 6) * sizeof(char) );
	if( ! new_fmt ) {
		EXCEPT( "_condor_gcb_dprintf_va() out of memory!" );
	}
	snprintf( new_fmt, len + 6, "GCB: %s", fmt );
	_condor_dprintf_va( flags, new_fmt, args );
	free( new_fmt );
}
#endif /* HAVE_EXT_GCB */
<|endoftext|>


<commit_before>/* CloneKernelConn.cpp
 *
 * Created on: May 23, 2011
 *     Author: peteschultz
 */

#include "CloneKernelConn.hpp"

namespace PV {

CloneKernelConn::CloneKernelConn(){
   initialize_base();
}

CloneKernelConn::CloneKernelConn(const char * name, HyPerCol * hc,
      const char * pre_layer_name, const char * post_layer_name,
      const char * original_kernelconn_name) {
   initialize_base();
   initialize(name, hc, pre_layer_name, post_layer_name, original_kernelconn_name);
}

int CloneKernelConn::initialize_base() {
   originalConn = NULL;
   return PV_SUCCESS;
}

int CloneKernelConn::initialize(const char * name, HyPerCol * hc,
      const char * pre_layer_name, const char * post_layer_name,
      const char * original_kernelconn_name) {
   InitCloneKernelWeights * weightInit = new InitCloneKernelWeights();
   assert(weightInit != NULL);
   int status = KernelConn::initialize(name, hc, pre_layer_name, post_layer_name, NULL, weightInit);
   if (original_kernelconn_name==NULL) {
      fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: originalConnName must be set.\n",
            name, hc->columnId());
      abort();
   }
   originalConnName = strdup(original_kernelconn_name);
   if (originalConnName == NULL) {
      fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: unable to allocate memory for originalConnName \"%s\": %s\n",
            name, hc->columnId(), original_kernelconn_name, strerror(errno));
      abort();
   }
   return status;
}

//int CloneKernelConn::setPatchSize(const char * filename) {
//   // nxp, nyp, nfp were set by the read-methods called by HyPerConn::setParams
//   assert(filename == NULL);
//   int xScalePre = pre->getXScale();
//   int xScalePost = post->getXScale();
//   int status = checkPatchSize(nxp, xScalePre, xScalePost, 'x');
//   if( status == PV_SUCCESS) {
//      int yScalePre = pre->getYScale();
//      int yScalePost = post->getYScale();
//      status = checkPatchSize(nyp, yScalePre, yScalePost, 'y');
//   }
//   return status;
//}

int CloneKernelConn::initNormalize() {
   normalizer = NULL;
   // normalize_flag = false; // replaced by testing whether normalizer!=NULL
   return PV_SUCCESS;
}

int CloneKernelConn::constructWeights(const char * filename) {
   int status = PV_SUCCESS;

   // CloneKernelConn::readShrinkPatches does nothing; shrinkPatches_flag is set in communicateInitInfo()
   // if( status == PV_SUCCESS ) readShrinkPatches(parent->parameters());

   // if( status == PV_SUCCESS ) status = setPatchSize(NULL);
   if( status == PV_SUCCESS ) status = setPatchStrides();

   wPatches = this->originalConn->get_wPatches();
   wDataStart = this->originalConn->get_wDataStart();
   gSynPatchStart = this->originalConn->getGSynPatchStart();
   aPostOffset = this->originalConn->getAPostOffset();
   dwDataStart = this->originalConn->get_dwDataStart();

//   for( int arbor=0; arbor<numberOfAxonalArborLists(); arbor++) {
//      get_wDataStart()[arbor] = originalConn->get_wDataStart(arbor);
//      get_wPatches()[arbor] = originalConn->weights(arbor);
//      // this->setKernelPatches(originalConn->getKernelPatches(arbor),arbor);
//      if( status == PV_SUCCESS )
//         status = createAxonalArbors(arbor); // sets gSynPatchStart[arbor][*] and aPostOffset[arbor][*]
//      if( status != PV_SUCCESS ) break;
//   }

   // Don't call initPlasticityPatches since plasticityFlag is always false.
   // Don't call shrinkPatches() since the original connection will have already shrunk patches
   return status;
}

void CloneKernelConn::constructWeightsOutOfMemory() {
   connOutOfMemory("CloneKernelConn::constructWeightsOutOfMemory()");
}

int CloneKernelConn::createAxonalArbors(int arborId) {
//   int numPatches = getNumWeightPatches();
//   for( int kex = 0; kex < numPatches; kex++ ) {
//      // kex is in extended frame, this makes transformations more difficult
//      int kl, offset, nxPatch, nyPatch, dx, dy;
//      calcPatchSize(arborId, kex, &kl, &offset, &nxPatch, &nyPatch, &dx, &dy);
//      pvdata_t * gSyn = post->getChannel(channel) + kl;
//      getGSynPatchStart()[arborId][kex] = gSyn;
//      getAPostOffset()[arborId][kex] = offset;
//      // Don't call pvpatch_adjust because weight patches point to the
//      // original conn's weight patches, which were already shrunk.
//   }
   return PV_SUCCESS;
}

PVPatch *** CloneKernelConn::initializeWeights(PVPatch *** patches, pvdata_t ** dataStart,
      int numPatches, const char * filename) {
   return patches;
   // nothing to be done as the weight patches point to originalConn's space.
}

void CloneKernelConn::readShrinkPatches(PVParams * params) {
   // During the communication phase, shrinkPatches_flag will be copied from originalConn
}

int CloneKernelConn::setParams(PVParams * params) {
   return KernelConn::setParams(params);
}

void CloneKernelConn::readNumAxonalArbors(PVParams * params) {
   // During the communication phase, numAxonalArbors will be copied from originalConn
}

void CloneKernelConn::readPlasticityFlag(PVParams * params) {
   plasticityFlag = false; // CloneKernelConn updates automatically, since it's done using pointer magic.
}

int CloneKernelConn::readPatchSize(PVParams * params) {
   // During the communication phase, nxp, nyp, nxpShrunken, nypShrunken will be copied from originalConn
   return PV_SUCCESS;
}

int CloneKernelConn::readNfp(PVParams * params) {
   // During the communication phase, nfp will be copied from originalConn
   return PV_SUCCESS;
}

int CloneKernelConn::communicateInitInfo() {
   // Need to set originalConn before calling KernelConn::communicate, since KernelConn::communicate calls setPatchSize, which needs originalConn.
   HyPerConn * origHyPerConn = parent->getConnFromName(originalConnName);
   if (origHyPerConn == NULL) {
      fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: originalConnName \"%s\" is not a connection in the column.\n",
            name, parent->columnId(), originalConnName);
   }
   originalConn = dynamic_cast<KernelConn *>(origHyPerConn);
   if (originalConn == NULL) {
      fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: originalConnName \"%s\" must be a KernelConn or a KernelConn-derived class.\n",
            name, parent->columnId(), originalConnName);
   }

   numAxonalArborLists = originalConn->numberOfAxonalArborLists();
   int status = KernelConn::communicateInitInfo();
   if (status != PV_SUCCESS) return status;

   // Presynaptic layers of the CloneKernelConn and its original conn must have the same size, or the patches won't line up with each other.
   const PVLayerLoc * preLoc = pre->getLayerLoc();
   const PVLayerLoc * origPreLoc = originalConn->preSynapticLayer()->getLayerLoc();

   if (preLoc->nx != origPreLoc->nx || preLoc->ny != origPreLoc->ny || preLoc->nf != origPreLoc->nf || preLoc->nb != origPreLoc->nb ) {
      if (parent->icCommunicator()->commRank()==0) {
         fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: CloneKernelConn and originalConn \"%s\" must have presynaptic layers with the same geometry (including margin width).\n",
               name, parent->columnId(), originalConn->getName());
         fprintf(stderr, "{nx=%d, ny=%d, nf=%d, nb=%d} versus {nx=%d, ny=%d, nf=%d, nb=%d}\n",
                 preLoc->nx, preLoc->ny, preLoc->nf, preLoc->nb, origPreLoc->nx, origPreLoc->ny, origPreLoc->nf, origPreLoc->nb);
      }
      abort();
   }

   //Redudent read in case it's a clone of a clone
   numAxonalArborLists = originalConn->numberOfAxonalArborLists();
   shrinkPatches_flag = originalConn->getShrinkPatches_flag();

   return status;
}

int CloneKernelConn::setPatchSize() {
   assert(originalConn);
   nxp = originalConn->xPatchSize();
   nyp = originalConn->yPatchSize();
   nxpShrunken = originalConn->getNxpShrunken();
   nypShrunken = originalConn->getNypShrunken();
   nfp = originalConn->fPatchSize();
   return PV_SUCCESS;
}

int CloneKernelConn::updateState(double time, double dt) {
   lastUpdateTime = originalConn->getLastUpdateTime();
   return PV_SUCCESS;
}

int CloneKernelConn::deleteWeights() {
   // Have to make sure not to free memory belonging to originalConn.
   // Set pointers that point into originalConn to NULL so that free() has no effect
   // when KernelConn::deleteWeights or HyPerConn::deleteWeights is called
	   wPatches = NULL;
	   wDataStart = NULL;
	   gSynPatchStart = NULL;
	   aPostOffset = NULL;
	   dwDataStart = NULL;
//   for(int arbor=0; arbor<numberOfAxonalArborLists(); arbor++) {
//      get_wPatches()[arbor] = NULL;
//      set_wDataStart(arbor,NULL);
//   }
   // set_kernelPatches(NULL);

   return 0; // HyPerConn::deleteWeights(); // HyPerConn destructor calls HyPerConn::deleteWeights()
}

CloneKernelConn::~CloneKernelConn() {
   deleteWeights();
}

} // end namespace PV
<commit_msg>Added update timer.<commit_after>/* CloneKernelConn.cpp
 *
 * Created on: May 23, 2011
 *     Author: peteschultz
 */

#include "CloneKernelConn.hpp"

namespace PV {

CloneKernelConn::CloneKernelConn(){
   initialize_base();
}

CloneKernelConn::CloneKernelConn(const char * name, HyPerCol * hc,
      const char * pre_layer_name, const char * post_layer_name,
      const char * original_kernelconn_name) {
   initialize_base();
   initialize(name, hc, pre_layer_name, post_layer_name, original_kernelconn_name);
}

int CloneKernelConn::initialize_base() {
   originalConn = NULL;
   return PV_SUCCESS;
}

int CloneKernelConn::initialize(const char * name, HyPerCol * hc,
      const char * pre_layer_name, const char * post_layer_name,
      const char * original_kernelconn_name) {
   InitCloneKernelWeights * weightInit = new InitCloneKernelWeights();
   assert(weightInit != NULL);
   int status = KernelConn::initialize(name, hc, pre_layer_name, post_layer_name, NULL, weightInit);
   if (original_kernelconn_name==NULL) {
      fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: originalConnName must be set.\n",
            name, hc->columnId());
      abort();
   }
   originalConnName = strdup(original_kernelconn_name);
   if (originalConnName == NULL) {
      fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: unable to allocate memory for originalConnName \"%s\": %s\n",
            name, hc->columnId(), original_kernelconn_name, strerror(errno));
      abort();
   }
   return status;
}

//int CloneKernelConn::setPatchSize(const char * filename) {
//   // nxp, nyp, nfp were set by the read-methods called by HyPerConn::setParams
//   assert(filename == NULL);
//   int xScalePre = pre->getXScale();
//   int xScalePost = post->getXScale();
//   int status = checkPatchSize(nxp, xScalePre, xScalePost, 'x');
//   if( status == PV_SUCCESS) {
//      int yScalePre = pre->getYScale();
//      int yScalePost = post->getYScale();
//      status = checkPatchSize(nyp, yScalePre, yScalePost, 'y');
//   }
//   return status;
//}

int CloneKernelConn::initNormalize() {
   normalizer = NULL;
   // normalize_flag = false; // replaced by testing whether normalizer!=NULL
   return PV_SUCCESS;
}

int CloneKernelConn::constructWeights(const char * filename) {
   int status = PV_SUCCESS;

   // CloneKernelConn::readShrinkPatches does nothing; shrinkPatches_flag is set in communicateInitInfo()
   // if( status == PV_SUCCESS ) readShrinkPatches(parent->parameters());

   // if( status == PV_SUCCESS ) status = setPatchSize(NULL);
   if( status == PV_SUCCESS ) status = setPatchStrides();

   wPatches = this->originalConn->get_wPatches();
   wDataStart = this->originalConn->get_wDataStart();
   gSynPatchStart = this->originalConn->getGSynPatchStart();
   aPostOffset = this->originalConn->getAPostOffset();
   dwDataStart = this->originalConn->get_dwDataStart();

//   for( int arbor=0; arbor<numberOfAxonalArborLists(); arbor++) {
//      get_wDataStart()[arbor] = originalConn->get_wDataStart(arbor);
//      get_wPatches()[arbor] = originalConn->weights(arbor);
//      // this->setKernelPatches(originalConn->getKernelPatches(arbor),arbor);
//      if( status == PV_SUCCESS )
//         status = createAxonalArbors(arbor); // sets gSynPatchStart[arbor][*] and aPostOffset[arbor][*]
//      if( status != PV_SUCCESS ) break;
//   }

   // Don't call initPlasticityPatches since plasticityFlag is always false.
   // Don't call shrinkPatches() since the original connection will have already shrunk patches
   return status;
}

void CloneKernelConn::constructWeightsOutOfMemory() {
   connOutOfMemory("CloneKernelConn::constructWeightsOutOfMemory()");
}

int CloneKernelConn::createAxonalArbors(int arborId) {
//   int numPatches = getNumWeightPatches();
//   for( int kex = 0; kex < numPatches; kex++ ) {
//      // kex is in extended frame, this makes transformations more difficult
//      int kl, offset, nxPatch, nyPatch, dx, dy;
//      calcPatchSize(arborId, kex, &kl, &offset, &nxPatch, &nyPatch, &dx, &dy);
//      pvdata_t * gSyn = post->getChannel(channel) + kl;
//      getGSynPatchStart()[arborId][kex] = gSyn;
//      getAPostOffset()[arborId][kex] = offset;
//      // Don't call pvpatch_adjust because weight patches point to the
//      // original conn's weight patches, which were already shrunk.
//   }
   return PV_SUCCESS;
}

PVPatch *** CloneKernelConn::initializeWeights(PVPatch *** patches, pvdata_t ** dataStart,
      int numPatches, const char * filename) {
   return patches;
   // nothing to be done as the weight patches point to originalConn's space.
}

void CloneKernelConn::readShrinkPatches(PVParams * params) {
   // During the communication phase, shrinkPatches_flag will be copied from originalConn
}

int CloneKernelConn::setParams(PVParams * params) {
   return KernelConn::setParams(params);
}

void CloneKernelConn::readNumAxonalArbors(PVParams * params) {
   // During the communication phase, numAxonalArbors will be copied from originalConn
}

void CloneKernelConn::readPlasticityFlag(PVParams * params) {
   plasticityFlag = false; // CloneKernelConn updates automatically, since it's done using pointer magic.
}

int CloneKernelConn::readPatchSize(PVParams * params) {
   // During the communication phase, nxp, nyp, nxpShrunken, nypShrunken will be copied from originalConn
   return PV_SUCCESS;
}

int CloneKernelConn::readNfp(PVParams * params) {
   // During the communication phase, nfp will be copied from originalConn
   return PV_SUCCESS;
}

int CloneKernelConn::communicateInitInfo() {
   // Need to set originalConn before calling KernelConn::communicate, since KernelConn::communicate calls setPatchSize, which needs originalConn.
   HyPerConn * origHyPerConn = parent->getConnFromName(originalConnName);
   if (origHyPerConn == NULL) {
      fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: originalConnName \"%s\" is not a connection in the column.\n",
            name, parent->columnId(), originalConnName);
   }
   originalConn = dynamic_cast<KernelConn *>(origHyPerConn);
   if (originalConn == NULL) {
      fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: originalConnName \"%s\" must be a KernelConn or a KernelConn-derived class.\n",
            name, parent->columnId(), originalConnName);
   }

   numAxonalArborLists = originalConn->numberOfAxonalArborLists();
   int status = KernelConn::communicateInitInfo();
   if (status != PV_SUCCESS) return status;

   // Presynaptic layers of the CloneKernelConn and its original conn must have the same size, or the patches won't line up with each other.
   const PVLayerLoc * preLoc = pre->getLayerLoc();
   const PVLayerLoc * origPreLoc = originalConn->preSynapticLayer()->getLayerLoc();

   if (preLoc->nx != origPreLoc->nx || preLoc->ny != origPreLoc->ny || preLoc->nf != origPreLoc->nf || preLoc->nb != origPreLoc->nb ) {
      if (parent->icCommunicator()->commRank()==0) {
         fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: CloneKernelConn and originalConn \"%s\" must have presynaptic layers with the same geometry (including margin width).\n",
               name, parent->columnId(), originalConn->getName());
         fprintf(stderr, "{nx=%d, ny=%d, nf=%d, nb=%d} versus {nx=%d, ny=%d, nf=%d, nb=%d}\n",
                 preLoc->nx, preLoc->ny, preLoc->nf, preLoc->nb, origPreLoc->nx, origPreLoc->ny, origPreLoc->nf, origPreLoc->nb);
      }
      abort();
   }

   //Redudent read in case it's a clone of a clone
   numAxonalArborLists = originalConn->numberOfAxonalArborLists();
   shrinkPatches_flag = originalConn->getShrinkPatches_flag();

   return status;
}

int CloneKernelConn::setPatchSize() {
   assert(originalConn);
   nxp = originalConn->xPatchSize();
   nyp = originalConn->yPatchSize();
   nxpShrunken = originalConn->getNxpShrunken();
   nypShrunken = originalConn->getNypShrunken();
   nfp = originalConn->fPatchSize();
   return PV_SUCCESS;
}

int CloneKernelConn::updateState(double time, double dt) {
   update_timer->start();

   lastUpdateTime = originalConn->getLastUpdateTime();

   update_timer->stop();
   return PV_SUCCESS;
}

int CloneKernelConn::deleteWeights() {
   // Have to make sure not to free memory belonging to originalConn.
   // Set pointers that point into originalConn to NULL so that free() has no effect
   // when KernelConn::deleteWeights or HyPerConn::deleteWeights is called
	   wPatches = NULL;
	   wDataStart = NULL;
	   gSynPatchStart = NULL;
	   aPostOffset = NULL;
	   dwDataStart = NULL;
//   for(int arbor=0; arbor<numberOfAxonalArborLists(); arbor++) {
//      get_wPatches()[arbor] = NULL;
//      set_wDataStart(arbor,NULL);
//   }
   // set_kernelPatches(NULL);

   return 0; // HyPerConn::deleteWeights(); // HyPerConn destructor calls HyPerConn::deleteWeights()
}

CloneKernelConn::~CloneKernelConn() {
   deleteWeights();
}

} // end namespace PV
<|endoftext|>


<commit_before>/* CloneKernelConn.cpp
 *
 * Created on: May 23, 2011
 *     Author: peteschultz
 */

#include "CloneKernelConn.hpp"

namespace PV {

CloneKernelConn::CloneKernelConn(){
   initialize_base();
}

CloneKernelConn::CloneKernelConn(const char * name, HyPerCol * hc,
      const char * pre_layer_name, const char * post_layer_name,
      const char * original_kernelconn_name) {
   initialize_base();
   initialize(name, hc, pre_layer_name, post_layer_name, original_kernelconn_name);
}

int CloneKernelConn::initialize_base() {
   originalConn = NULL;
   return PV_SUCCESS;
}

int CloneKernelConn::initialize(const char * name, HyPerCol * hc,
      const char * pre_layer_name, const char * post_layer_name,
      const char * original_kernelconn_name) {
   InitCloneKernelWeights * weightInit = new InitCloneKernelWeights();
   assert(weightInit != NULL);
   int status = KernelConn::initialize(name, hc, pre_layer_name, post_layer_name, NULL, weightInit);
   if (original_kernelconn_name==NULL) {
      fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: originalConnName must be set.\n",
            name, hc->columnId());
      abort();
   }
   originalConnName = strdup(original_kernelconn_name);
   if (originalConnName == NULL) {
      fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: unable to allocate memory for originalConnName \"%s\": %s\n",
            name, hc->columnId(), original_kernelconn_name, strerror(errno));
      abort();
   }
   return status;
}

//int CloneKernelConn::setPatchSize(const char * filename) {
//   // nxp, nyp, nfp were set by the read-methods called by HyPerConn::setParams
//   assert(filename == NULL);
//   int xScalePre = pre->getXScale();
//   int xScalePost = post->getXScale();
//   int status = checkPatchSize(nxp, xScalePre, xScalePost, 'x');
//   if( status == PV_SUCCESS) {
//      int yScalePre = pre->getYScale();
//      int yScalePost = post->getYScale();
//      status = checkPatchSize(nyp, yScalePre, yScalePost, 'y');
//   }
//   return status;
//}

int CloneKernelConn::initNormalize() {
   normalizer = NULL;
   // normalize_flag = false; // replaced by testing whether normalizer!=NULL
   return PV_SUCCESS;
}

int CloneKernelConn::constructWeights(const char * filename) {
   int status = PV_SUCCESS;

   // CloneKernelConn::readShrinkPatches does nothing; shrinkPatches_flag is set in communicateInitInfo()
   // if( status == PV_SUCCESS ) readShrinkPatches(parent->parameters());

   // if( status == PV_SUCCESS ) status = setPatchSize(NULL);
   if( status == PV_SUCCESS ) status = setPatchStrides();

   wPatches = this->originalConn->get_wPatches();
   wDataStart = this->originalConn->get_wDataStart();
   gSynPatchStart = this->originalConn->getGSynPatchStart();
   aPostOffset = this->originalConn->getAPostOffset();
   dwDataStart = this->originalConn->get_dwDataStart();

//   for( int arbor=0; arbor<numberOfAxonalArborLists(); arbor++) {
//      get_wDataStart()[arbor] = originalConn->get_wDataStart(arbor);
//      get_wPatches()[arbor] = originalConn->weights(arbor);
//      // this->setKernelPatches(originalConn->getKernelPatches(arbor),arbor);
//      if( status == PV_SUCCESS )
//         status = createAxonalArbors(arbor); // sets gSynPatchStart[arbor][*] and aPostOffset[arbor][*]
//      if( status != PV_SUCCESS ) break;
//   }

   // Don't call initPlasticityPatches since plasticityFlag is always false.
   // Don't call shrinkPatches() since the original connection will have already shrunk patches
   return status;
}

void CloneKernelConn::constructWeightsOutOfMemory() {
   connOutOfMemory("CloneKernelConn::constructWeightsOutOfMemory()");
}

int CloneKernelConn::createAxonalArbors(int arborId) {
//   int numPatches = getNumWeightPatches();
//   for( int kex = 0; kex < numPatches; kex++ ) {
//      // kex is in extended frame, this makes transformations more difficult
//      int kl, offset, nxPatch, nyPatch, dx, dy;
//      calcPatchSize(arborId, kex, &kl, &offset, &nxPatch, &nyPatch, &dx, &dy);
//      pvdata_t * gSyn = post->getChannel(channel) + kl;
//      getGSynPatchStart()[arborId][kex] = gSyn;
//      getAPostOffset()[arborId][kex] = offset;
//      // Don't call pvpatch_adjust because weight patches point to the
//      // original conn's weight patches, which were already shrunk.
//   }
   return PV_SUCCESS;
}

PVPatch *** CloneKernelConn::initializeWeights(PVPatch *** patches, pvdata_t ** dataStart,
      int numPatches, const char * filename) {
   return patches;
   // nothing to be done as the weight patches point to originalConn's space.
}

// We override many read-methods because CloneKernelConn will use
// originalConn's values.  communicateInitInfo will check if the associated
// parameters exist in params for theCloneKernelConn group, and whether they
// are consistent with the originalConn parameters.
// If consistent, issue a warning that the param is unnecessary and continue.
// If inconsistent, issue an error and quit.
// We can't do that in the read-method because we can't be sure originalConn
// has set its own parameter yet (or even if it's been instantiated),
// and in theory originalConn could be a subclass that determines
// the parameter some way other than reading its own parameter
// group's param directly.

void CloneKernelConn::readShrinkPatches(PVParams * params) {
   // During the communication phase, shrinkPatches_flag will be copied from originalConn
}

int CloneKernelConn::setParams(PVParams * params) {
   return KernelConn::setParams(params);
}

void CloneKernelConn::readNumAxonalArbors(PVParams * params) {
   // During the communication phase, numAxonalArbors will be copied from originalConn
}

void CloneKernelConn::readPlasticityFlag(PVParams * params) {
   plasticityFlag = false; // CloneKernelConn updates automatically, since it's done using pointer magic.
   handleUnnecessaryIntParameter("plasticityFlag", plasticityFlag);
}

int CloneKernelConn::readPatchSize(PVParams * params) {
   // During the communication phase, nxp, nyp, nxpShrunken, nypShrunken will be copied from originalConn
   return PV_SUCCESS;
}

int CloneKernelConn::readNfp(PVParams * params) {
   // During the communication phase, nfp will be copied from originalConn
   return PV_SUCCESS;
}

int CloneKernelConn::communicateInitInfo() {
   // Need to set originalConn before calling KernelConn::communicate, since KernelConn::communicate calls setPatchSize, which needs originalConn.
   HyPerConn * origHyPerConn = parent->getConnFromName(originalConnName);
   if (origHyPerConn == NULL) {
      fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: originalConnName \"%s\" is not a connection in the column.\n",
            name, parent->columnId(), originalConnName);
   }
   originalConn = dynamic_cast<KernelConn *>(origHyPerConn);
   if (originalConn == NULL) {
      fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: originalConnName \"%s\" must be a KernelConn or a KernelConn-derived class.\n",
            name, parent->columnId(), originalConnName);
   }

   // Copy some parameters from originalConn.  Check if parameters exist is
   // the clone's param group, and issue a warning (if the param has the right
   // value) or an error (if it has the wrong value).
   int status = PV_SUCCESS;
   PVParams * params = parent->parameters();
   const char * classname = params->groupKeywordFromName(name);
   numAxonalArborLists = originalConn->numberOfAxonalArborLists();
   handleUnnecessaryIntParameter("numAxonalArbors", numAxonalArborLists);
   status = KernelConn::communicateInitInfo();
   if (status != PV_SUCCESS) return status;

   // Presynaptic layers of the CloneKernelConn and its original conn must have the same size, or the patches won't line up with each other.
   const PVLayerLoc * preLoc = pre->getLayerLoc();
   const PVLayerLoc * origPreLoc = originalConn->preSynapticLayer()->getLayerLoc();

   if (preLoc->nx != origPreLoc->nx || preLoc->ny != origPreLoc->ny || preLoc->nf != origPreLoc->nf || preLoc->nb != origPreLoc->nb ) {
      if (parent->icCommunicator()->commRank()==0) {
         fprintf(stderr, "%s \"%s\" error in rank %d process: CloneKernelConn and originalConn \"%s\" must have presynaptic layers with the same geometry (including margin width).\n",
               classname, name, parent->columnId(), originalConn->getName());
         fprintf(stderr, "{nx=%d, ny=%d, nf=%d, nb=%d} versus {nx=%d, ny=%d, nf=%d, nb=%d}\n",
                 preLoc->nx, preLoc->ny, preLoc->nf, preLoc->nb, origPreLoc->nx, origPreLoc->ny, origPreLoc->nf, origPreLoc->nb);
      }
      abort();
   }

   //Redudant read in case it's a clone of a clone
   numAxonalArborLists = originalConn->numberOfAxonalArborLists();
   shrinkPatches_flag = originalConn->getShrinkPatches_flag();
   handleUnnecessaryIntParameter("shrinkPatches", shrinkPatches_flag);

   return status;
}

int CloneKernelConn::setPatchSize() {
   assert(originalConn);
   nxp = originalConn->xPatchSize();
   nyp = originalConn->yPatchSize();
   nxpShrunken = originalConn->getNxpShrunken();
   nypShrunken = originalConn->getNypShrunken();
   nfp = originalConn->fPatchSize();
   handleUnnecessaryIntParameter("nxp", nxp);
   handleUnnecessaryIntParameter("nyp", nyp);
   handleUnnecessaryIntParameter("nxpShrunken", nxpShrunken);
   handleUnnecessaryIntParameter("nypShrunken", nypShrunken);
   handleUnnecessaryIntParameter("nfp", nfp);
   return PV_SUCCESS;
}

int CloneKernelConn::updateState(double time, double dt) {
   update_timer->start();

   lastUpdateTime = originalConn->getLastUpdateTime();

   update_timer->stop();
   return PV_SUCCESS;
}

int CloneKernelConn::deleteWeights() {
   // Have to make sure not to free memory belonging to originalConn.
   // Set pointers that point into originalConn to NULL so that free() has no effect
   // when KernelConn::deleteWeights or HyPerConn::deleteWeights is called
	   wPatches = NULL;
	   wDataStart = NULL;
	   gSynPatchStart = NULL;
	   aPostOffset = NULL;
	   dwDataStart = NULL;
//   for(int arbor=0; arbor<numberOfAxonalArborLists(); arbor++) {
//      get_wPatches()[arbor] = NULL;
//      set_wDataStart(arbor,NULL);
//   }
   // set_kernelPatches(NULL);

   return 0; // HyPerConn::deleteWeights(); // HyPerConn destructor calls HyPerConn::deleteWeights()
}

CloneKernelConn::~CloneKernelConn() {
   free(originalConnName);
   deleteWeights();
}

} // end namespace PV
<commit_msg>presynaptic layers of a CloneKernelConn and its original conn keep their margin widths synchronized instead of checking that they're equal and failing if not.<commit_after>/* CloneKernelConn.cpp
 *
 * Created on: May 23, 2011
 *     Author: peteschultz
 */

#include "CloneKernelConn.hpp"

namespace PV {

CloneKernelConn::CloneKernelConn(){
   initialize_base();
}

CloneKernelConn::CloneKernelConn(const char * name, HyPerCol * hc,
      const char * pre_layer_name, const char * post_layer_name,
      const char * original_kernelconn_name) {
   initialize_base();
   initialize(name, hc, pre_layer_name, post_layer_name, original_kernelconn_name);
}

int CloneKernelConn::initialize_base() {
   originalConn = NULL;
   return PV_SUCCESS;
}

int CloneKernelConn::initialize(const char * name, HyPerCol * hc,
      const char * pre_layer_name, const char * post_layer_name,
      const char * original_kernelconn_name) {
   InitCloneKernelWeights * weightInit = new InitCloneKernelWeights();
   assert(weightInit != NULL);
   int status = KernelConn::initialize(name, hc, pre_layer_name, post_layer_name, NULL, weightInit);
   if (original_kernelconn_name==NULL) {
      fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: originalConnName must be set.\n",
            name, hc->columnId());
      abort();
   }
   originalConnName = strdup(original_kernelconn_name);
   if (originalConnName == NULL) {
      fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: unable to allocate memory for originalConnName \"%s\": %s\n",
            name, hc->columnId(), original_kernelconn_name, strerror(errno));
      abort();
   }
   return status;
}

//int CloneKernelConn::setPatchSize(const char * filename) {
//   // nxp, nyp, nfp were set by the read-methods called by HyPerConn::setParams
//   assert(filename == NULL);
//   int xScalePre = pre->getXScale();
//   int xScalePost = post->getXScale();
//   int status = checkPatchSize(nxp, xScalePre, xScalePost, 'x');
//   if( status == PV_SUCCESS) {
//      int yScalePre = pre->getYScale();
//      int yScalePost = post->getYScale();
//      status = checkPatchSize(nyp, yScalePre, yScalePost, 'y');
//   }
//   return status;
//}

int CloneKernelConn::initNormalize() {
   normalizer = NULL;
   // normalize_flag = false; // replaced by testing whether normalizer!=NULL
   return PV_SUCCESS;
}

int CloneKernelConn::constructWeights(const char * filename) {
   int status = PV_SUCCESS;

   // CloneKernelConn::readShrinkPatches does nothing; shrinkPatches_flag is set in communicateInitInfo()
   // if( status == PV_SUCCESS ) readShrinkPatches(parent->parameters());

   // if( status == PV_SUCCESS ) status = setPatchSize(NULL);
   if( status == PV_SUCCESS ) status = setPatchStrides();

   wPatches = this->originalConn->get_wPatches();
   wDataStart = this->originalConn->get_wDataStart();
   gSynPatchStart = this->originalConn->getGSynPatchStart();
   aPostOffset = this->originalConn->getAPostOffset();
   dwDataStart = this->originalConn->get_dwDataStart();

//   for( int arbor=0; arbor<numberOfAxonalArborLists(); arbor++) {
//      get_wDataStart()[arbor] = originalConn->get_wDataStart(arbor);
//      get_wPatches()[arbor] = originalConn->weights(arbor);
//      // this->setKernelPatches(originalConn->getKernelPatches(arbor),arbor);
//      if( status == PV_SUCCESS )
//         status = createAxonalArbors(arbor); // sets gSynPatchStart[arbor][*] and aPostOffset[arbor][*]
//      if( status != PV_SUCCESS ) break;
//   }

   // Don't call initPlasticityPatches since plasticityFlag is always false.
   // Don't call shrinkPatches() since the original connection will have already shrunk patches
   return status;
}

void CloneKernelConn::constructWeightsOutOfMemory() {
   connOutOfMemory("CloneKernelConn::constructWeightsOutOfMemory()");
}

int CloneKernelConn::createAxonalArbors(int arborId) {
//   int numPatches = getNumWeightPatches();
//   for( int kex = 0; kex < numPatches; kex++ ) {
//      // kex is in extended frame, this makes transformations more difficult
//      int kl, offset, nxPatch, nyPatch, dx, dy;
//      calcPatchSize(arborId, kex, &kl, &offset, &nxPatch, &nyPatch, &dx, &dy);
//      pvdata_t * gSyn = post->getChannel(channel) + kl;
//      getGSynPatchStart()[arborId][kex] = gSyn;
//      getAPostOffset()[arborId][kex] = offset;
//      // Don't call pvpatch_adjust because weight patches point to the
//      // original conn's weight patches, which were already shrunk.
//   }
   return PV_SUCCESS;
}

PVPatch *** CloneKernelConn::initializeWeights(PVPatch *** patches, pvdata_t ** dataStart,
      int numPatches, const char * filename) {
   return patches;
   // nothing to be done as the weight patches point to originalConn's space.
}

// We override many read-methods because CloneKernelConn will use
// originalConn's values.  communicateInitInfo will check if the associated
// parameters exist in params for theCloneKernelConn group, and whether they
// are consistent with the originalConn parameters.
// If consistent, issue a warning that the param is unnecessary and continue.
// If inconsistent, issue an error and quit.
// We can't do that in the read-method because we can't be sure originalConn
// has set its own parameter yet (or even if it's been instantiated),
// and in theory originalConn could be a subclass that determines
// the parameter some way other than reading its own parameter
// group's param directly.

void CloneKernelConn::readShrinkPatches(PVParams * params) {
   // During the communication phase, shrinkPatches_flag will be copied from originalConn
}

int CloneKernelConn::setParams(PVParams * params) {
   return KernelConn::setParams(params);
}

void CloneKernelConn::readNumAxonalArbors(PVParams * params) {
   // During the communication phase, numAxonalArbors will be copied from originalConn
}

void CloneKernelConn::readPlasticityFlag(PVParams * params) {
   plasticityFlag = false; // CloneKernelConn updates automatically, since it's done using pointer magic.
   handleUnnecessaryIntParameter("plasticityFlag", plasticityFlag);
}

int CloneKernelConn::readPatchSize(PVParams * params) {
   // During the communication phase, nxp, nyp, nxpShrunken, nypShrunken will be copied from originalConn
   return PV_SUCCESS;
}

int CloneKernelConn::readNfp(PVParams * params) {
   // During the communication phase, nfp will be copied from originalConn
   return PV_SUCCESS;
}

int CloneKernelConn::communicateInitInfo() {
   // Need to set originalConn before calling KernelConn::communicate, since KernelConn::communicate calls setPatchSize, which needs originalConn.
   HyPerConn * origHyPerConn = parent->getConnFromName(originalConnName);
   if (origHyPerConn == NULL) {
      fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: originalConnName \"%s\" is not a connection in the column.\n",
            name, parent->columnId(), originalConnName);
   }
   originalConn = dynamic_cast<KernelConn *>(origHyPerConn);
   if (originalConn == NULL) {
      fprintf(stderr, "CloneKernelConn \"%s\" error in rank %d process: originalConnName \"%s\" must be a KernelConn or a KernelConn-derived class.\n",
            name, parent->columnId(), originalConnName);
   }

   // Copy some parameters from originalConn.  Check if parameters exist is
   // the clone's param group, and issue a warning (if the param has the right
   // value) or an error (if it has the wrong value).
   int status = PV_SUCCESS;
   PVParams * params = parent->parameters();
   const char * classname = params->groupKeywordFromName(name);
   numAxonalArborLists = originalConn->numberOfAxonalArborLists();
   handleUnnecessaryIntParameter("numAxonalArbors", numAxonalArborLists);
   status = KernelConn::communicateInitInfo();
   if (status != PV_SUCCESS) return status;

   // Presynaptic layers of the CloneKernelConn and its original conn must have the same size, or the patches won't line up with each other.
   const PVLayerLoc * preLoc = pre->getLayerLoc();
   const PVLayerLoc * origPreLoc = originalConn->preSynapticLayer()->getLayerLoc();

   if (preLoc->nx != origPreLoc->nx || preLoc->ny != origPreLoc->ny || preLoc->nf != origPreLoc->nf ) {
      if (parent->icCommunicator()->commRank()==0) {
         fprintf(stderr, "%s \"%s\" error in rank %d process: CloneKernelConn and originalConn \"%s\" must have presynaptic layers with the same nx,ny,nf.\n",
               classname, name, parent->columnId(), originalConn->getName());
         fprintf(stderr, "{nx=%d, ny=%d, nf=%d} versus {nx=%d, ny=%d, nf=%d}\n",
                 preLoc->nx, preLoc->ny, preLoc->nf, origPreLoc->nx, origPreLoc->ny, origPreLoc->nf);
      }
      abort();
   }

   // Make sure the original's and the clone's margin widths stay equal
   originalConn->preSynapticLayer()->synchronizeMarginWidth(pre);
   pre->synchronizeMarginWidth(originalConn->preSynapticLayer());

   //Redudant read in case it's a clone of a clone
   numAxonalArborLists = originalConn->numberOfAxonalArborLists();
   shrinkPatches_flag = originalConn->getShrinkPatches_flag();
   handleUnnecessaryIntParameter("shrinkPatches", shrinkPatches_flag);

   return status;
}

int CloneKernelConn::setPatchSize() {
   assert(originalConn);
   nxp = originalConn->xPatchSize();
   nyp = originalConn->yPatchSize();
   nxpShrunken = originalConn->getNxpShrunken();
   nypShrunken = originalConn->getNypShrunken();
   nfp = originalConn->fPatchSize();
   handleUnnecessaryIntParameter("nxp", nxp);
   handleUnnecessaryIntParameter("nyp", nyp);
   handleUnnecessaryIntParameter("nxpShrunken", nxpShrunken);
   handleUnnecessaryIntParameter("nypShrunken", nypShrunken);
   handleUnnecessaryIntParameter("nfp", nfp);
   return PV_SUCCESS;
}

int CloneKernelConn::updateState(double time, double dt) {
   update_timer->start();

   lastUpdateTime = originalConn->getLastUpdateTime();

   update_timer->stop();
   return PV_SUCCESS;
}

int CloneKernelConn::deleteWeights() {
   // Have to make sure not to free memory belonging to originalConn.
   // Set pointers that point into originalConn to NULL so that free() has no effect
   // when KernelConn::deleteWeights or HyPerConn::deleteWeights is called
	   wPatches = NULL;
	   wDataStart = NULL;
	   gSynPatchStart = NULL;
	   aPostOffset = NULL;
	   dwDataStart = NULL;
//   for(int arbor=0; arbor<numberOfAxonalArborLists(); arbor++) {
//      get_wPatches()[arbor] = NULL;
//      set_wDataStart(arbor,NULL);
//   }
   // set_kernelPatches(NULL);

   return 0; // HyPerConn::deleteWeights(); // HyPerConn destructor calls HyPerConn::deleteWeights()
}

CloneKernelConn::~CloneKernelConn() {
   free(originalConnName);
   deleteWeights();
}

} // end namespace PV
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004-2019 musikcube team
//
// 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 author nor the names of other 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.
//
//////////////////////////////////////////////////////////////////////////////

#include "pch.hpp"
#include <core/library/LibraryFactory.h>
#include <core/library/LocalLibrary.h>
#include <core/library/RemoteLibrary.h>
#include <core/db/Connection.h>
#include <core/support/Common.h>
#include <core/support/Preferences.h>
#include <core/support/PreferenceKeys.h>

using namespace musik::core;

static LibraryFactory::IMessageQueue* sMessageQueue = nullptr;
static std::shared_ptr<LibraryFactory> sInstance;

void LibraryFactory::Initialize(IMessageQueue& messageQueue) {
    sMessageQueue = &messageQueue;
}

LibraryFactory& LibraryFactory::Instance() {
    if (!sInstance) {
        sInstance = std::shared_ptr<LibraryFactory>(new LibraryFactory());
    }
    return *sInstance;
};

LibraryFactory::LibraryFactory() {
    auto prefs = Preferences::ForComponent(prefs::components::Libraries);
    std::vector<std::string> libraries;
    prefs->GetKeys(libraries);

    for (size_t i = 0; i < libraries.size(); i++) {
        std::string name = libraries.at(i);
        int id = prefs->GetInt(name);
        this->AddLibrary(id, LibraryType::Local, name);
    }

    if (this->libraries.empty()) {
        this->CreateLibrary("Local Library", LibraryType::Local);
    }
}

LibraryFactory::~LibraryFactory() {
}

ILibraryPtr LibraryFactory::AddLibrary(int id, LibraryType type, const std::string& name) {
    ILibraryPtr library = (type == LibraryType::Local)
        ? library::LocalLibrary::Create(name, id)
        : library::RemoteLibrary::Create(name, id);

    if (library) {
        if (sMessageQueue) {
            library->SetMessageQueue(*sMessageQueue);
        }
        this->libraries.push_back(library);
        this->libraryMap[id] = library;
        this->LibrariesUpdated();
    }

    return library;
}

void LibraryFactory::Shutdown() {
    if (sInstance) {
        for (ILibraryPtr library : sInstance->libraries) {
            library->Close();
        }
        sInstance->libraries.clear();
    }
}

ILibraryPtr LibraryFactory::CreateLibrary(const std::string& name, LibraryType type) {
    auto prefs = Preferences::ForComponent(prefs::components::Libraries);
    std::vector<std::string> libraries;
    prefs->GetKeys(libraries);

    /* ensure the library doesn't already exist, and figure out a
    new unique identifier for this one... */

    int existingId = -1;
    int nextId = 0; /* we start at 1 becuase we always have. */
    for (size_t i = 0; i < libraries.size(); i++) {
        std::string n = libraries.at(i);
        int id = prefs->GetInt(name);

        if (n == name) {
            /* we already created a library with this name, let's go ahead
            and look it up and return it. */
            existingId = id;
            break;
        }

        if (id > nextId) {
            nextId = id;
        }
    }

    if (existingId != -1) {
        return this->GetLibrary(existingId);
    }

    ++nextId; /* unique */
    prefs->SetInt(name, nextId);

    return this->AddLibrary(nextId, type, name);
}

LibraryFactory::LibraryVector LibraryFactory::Libraries() {
    return LibraryFactory::Instance().libraries;
}

ILibraryPtr LibraryFactory::Default() {
    return LibraryFactory::Instance().libraries.at(0);
}

ILibraryPtr LibraryFactory::GetLibrary(int identifier) {
    if (identifier) {
        LibraryMap::iterator lib = this->libraryMap.find(identifier);
        if (lib != this->libraryMap.end()) {
            return lib->second;
        }
    }
    return ILibraryPtr();
}

<commit_msg>More LibraryFactory bug fixes. This thing needs to be rethought.<commit_after>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004-2019 musikcube team
//
// 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 author nor the names of other 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.
//
//////////////////////////////////////////////////////////////////////////////

#include "pch.hpp"
#include <core/library/LibraryFactory.h>
#include <core/library/LocalLibrary.h>
#include <core/library/RemoteLibrary.h>
#include <core/db/Connection.h>
#include <core/support/Common.h>
#include <core/support/Preferences.h>
#include <core/support/PreferenceKeys.h>

using namespace musik::core;

static LibraryFactory::IMessageQueue* sMessageQueue = nullptr;
static std::shared_ptr<LibraryFactory> sInstance;

void LibraryFactory::Initialize(IMessageQueue& messageQueue) {
    sMessageQueue = &messageQueue;
}

LibraryFactory& LibraryFactory::Instance() {
    if (!sInstance) {
        sInstance = std::shared_ptr<LibraryFactory>(new LibraryFactory());
    }
    return *sInstance;
};

LibraryFactory::LibraryFactory() {
    this->CreateLibrary("Local Library", LibraryType::Local);
}

LibraryFactory::~LibraryFactory() {
}

ILibraryPtr LibraryFactory::AddLibrary(int id, LibraryType type, const std::string& name) {
    ILibraryPtr library = (type == LibraryType::Local)
        ? library::LocalLibrary::Create(name, id)
        : library::RemoteLibrary::Create(name, id);

    if (library) {
        if (sMessageQueue) {
            library->SetMessageQueue(*sMessageQueue);
        }
        this->libraries.push_back(library);
        this->libraryMap[id] = library;
        this->LibrariesUpdated();
    }

    return library;
}

void LibraryFactory::Shutdown() {
    if (sInstance) {
        for (ILibraryPtr library : sInstance->libraries) {
            library->Close();
        }
        sInstance->libraries.clear();
    }
}

ILibraryPtr LibraryFactory::CreateLibrary(const std::string& name, LibraryType type) {
    auto prefs = Preferences::ForComponent(prefs::components::Libraries);
    std::vector<std::string> libraries;
    prefs->GetKeys(libraries);

    /* ensure the library doesn't already exist, and figure out a
    new unique identifier for this one... */

    int existingId = -1;
    int nextId = 0; /* we start at 1 becuase we always have. */
    for (size_t i = 0; i < libraries.size(); i++) {
        std::string n = libraries.at(i);
        int id = prefs->GetInt(name);

        if (n == name) {
            /* we already created a library with this name, let's go ahead
            and look it up and return it. */
            existingId = id;
            break;
        }

        if (id > nextId) {
            nextId = id;
        }
    }

    if (existingId != -1) {
        auto library = this->GetLibrary(existingId);
        if (!library) {
            return this->AddLibrary(existingId, type, name);
        }
    }

    ++nextId; /* unique */
    prefs->SetInt(name, nextId);

    return this->AddLibrary(nextId, type, name);
}

LibraryFactory::LibraryVector LibraryFactory::Libraries() {
    return LibraryFactory::Instance().libraries;
}

ILibraryPtr LibraryFactory::Default() {
    return LibraryFactory::Instance().libraries.at(0);
}

ILibraryPtr LibraryFactory::GetLibrary(int identifier) {
    if (identifier) {
        LibraryMap::iterator lib = this->libraryMap.find(identifier);
        if (lib != this->libraryMap.end()) {
            return lib->second;
        }
    }
    return ILibraryPtr();
}

<|endoftext|>


<commit_before>#include <cassert>
#include <cstring>
#include <sstream>
#include <sys/time.h>
#include <unordered_set>

#include <derecho/conf/conf.hpp>
#include <derecho/core/detail/p2p_connection_manager.hpp>
#include <derecho/sst/detail/poll_utils.hpp>

namespace sst {
P2PConnectionManager::P2PConnectionManager(const P2PParams params)
        : my_node_id(params.my_node_id),
          failure_upcall(params.failure_upcall) {

    // HARD-CODED. Adding another request type will break this

    request_params.window_sizes[P2P_REPLY] = params.p2p_window_size;
    request_params.window_sizes[P2P_REQUEST] = params.p2p_window_size;
    request_params.window_sizes[RPC_REPLY] = params.rpc_window_size;
    request_params.max_msg_sizes[P2P_REPLY] = params.max_p2p_reply_size;
    request_params.max_msg_sizes[P2P_REQUEST] = params.max_p2p_request_size;
    request_params.max_msg_sizes[RPC_REPLY] = params.max_rpc_reply_size;

    p2p_buf_size = 0;
    for(uint8_t i = 0; i < num_request_types; ++i) {
        request_params.offsets[i] = p2p_buf_size;
        p2p_buf_size += request_params.window_sizes[i] * request_params.max_msg_sizes[i];
    }
    p2p_buf_size += sizeof(bool);

    p2p_connections[my_node_id] = std::make_unique<P2PConnection>(my_node_id, my_node_id, p2p_buf_size, request_params);

    // external client doesn't need failure checking
    if (!params.is_external) {
        timeout_thread = std::thread(&P2PConnectionManager::check_failures_loop, this);
    }
}

P2PConnectionManager::~P2PConnectionManager() {
    shutdown_failures_thread();
}

void P2PConnectionManager::add_connections(const std::vector<node_id_t>& node_ids) {
    std::lock_guard<std::mutex> lock(connections_mutex);
    for (const node_id_t remote_id : node_ids) {
	if (p2p_connections.find(remote_id) == p2p_connections.end()) {
	    p2p_connections.emplace(remote_id, std::make_unique<P2PConnection>(my_node_id, remote_id, p2p_buf_size, request_params));
    	}
    }
}

void P2PConnectionManager::remove_connections(const std::vector<node_id_t>& node_ids) {
    std::lock_guard<std::mutex> lock(connections_mutex);
    for(const node_id_t remote_id : node_ids) {
        p2p_connections.erase(remote_id);
    }
}

void P2PConnectionManager::shutdown_failures_thread() {
    thread_shutdown = true;
    if(timeout_thread.joinable()) {
        timeout_thread.join();
    }
}

uint64_t P2PConnectionManager::get_max_p2p_reply_size() {
    return request_params.max_msg_sizes[P2P_REPLY] - sizeof(uint64_t);
}

void P2PConnectionManager::update_incoming_seq_num() {
    p2p_connections[last_node_id]->update_incoming_seq_num();
}

// check if there's a new request from any node
std::optional<std::pair<node_id_t, char*>> P2PConnectionManager::probe_all() {
    for(const auto& [node_id, p2p_conn] : p2p_connections) {
        auto buf = p2p_conn->probe();
        if(buf && buf[0]) {
            last_node_id = node_id;
            return std::pair<node_id_t, char*>(node_id, buf);
        } else if(buf) {
            // this means that we have a null reply
            // we don't need to process it, but we still want to increment the seq num
            p2p_conn->update_incoming_seq_num();
        }
    }
    return {};
}

char* P2PConnectionManager::get_sendbuffer_ptr(node_id_t node_id, REQUEST_TYPE type) {
    return p2p_connections.at(node_id)->get_sendbuffer_ptr(type);
}

void P2PConnectionManager::send(node_id_t node_id) {
    p2p_connections.at(node_id)->send();
    if(node_id != my_node_id) {
        p2p_connections.at(node_id)->num_rdma_writes++;
    }
}

void P2PConnectionManager::check_failures_loop() {
    pthread_setname_np(pthread_self(), "p2p_timeout");

    uint32_t heartbeat_ms = derecho::getConfUInt32(CONF_DERECHO_HEARTBEAT_MS);
    const auto tid = std::this_thread::get_id();
    // get id first
    uint32_t ce_idx = util::polling_data.get_index(tid);
    while(!thread_shutdown) {
        std::this_thread::sleep_for(std::chrono::milliseconds(heartbeat_ms));
        std::unordered_set<node_id_t> posted_write_to;

        util::polling_data.set_waiting(tid);
#ifdef USE_VERBS_API
        std::map<uint32_t, struct verbs_sender_ctxt> sctxt;
#else
        std::map<uint32_t, struct lf_sender_ctxt> sctxt;
#endif

        for(const auto& [node_id, p2p_conn] : p2p_connections) {
            if (node_id == my_node_id || p2p_conn->num_rdma_writes < 1000) {
                continue;
            }
            p2p_conn->num_rdma_writes = 0;
            sctxt[node_id].remote_id = node_id;
            sctxt[node_id].ce_idx = ce_idx;

            p2p_conn->get_res()->post_remote_write_with_completion(&sctxt[node_id], p2p_buf_size - sizeof(bool), sizeof(bool));
            posted_write_to.insert(node_id);
        }

        // track which nodes respond successfully
        std::unordered_set<node_id_t> polled_successfully_from;
        std::vector<node_id_t> failed_node_indexes;

        /** Completion Queue poll timeout in millisec */
        const int MAX_POLL_CQ_TIMEOUT = 2000;
        unsigned long start_time_msec;
        unsigned long cur_time_msec;
        struct timeval cur_time;

        // wait for completion for a while before giving up of doing it ..
        gettimeofday(&cur_time, NULL);
        start_time_msec = (cur_time.tv_sec * 1000) + (cur_time.tv_usec / 1000);

        uint32_t num_completions = 0;
        while(num_completions < p2p_connections.size() - 1) {
            std::optional<std::pair<int32_t, int32_t>> ce;
            while(true) {
                // check if polling result is available
                ce = util::polling_data.get_completion_entry(tid);
                if(ce) {
                    break;
                }
                gettimeofday(&cur_time, NULL);
                cur_time_msec = (cur_time.tv_sec * 1000) + (cur_time.tv_usec / 1000);
                if((cur_time_msec - start_time_msec) >= MAX_POLL_CQ_TIMEOUT) {
                    break;
                }
            }
            // if waiting for a completion entry timed out
            if(!ce) {
                // mark all nodes that have not yet responded as failed
                for(const auto& pair : p2p_connections) {
                    const auto& node_id = pair.first;
                    if(posted_write_to.find(node_id) == posted_write_to.end()
                    || polled_successfully_from.find(node_id) != polled_successfully_from.end()) {
                        continue;
                    }
                    failed_node_indexes.push_back(node_id);
                }
                break;
            }
            num_completions++;

            auto ce_v = ce.value();
            int remote_id = ce_v.first;
            int result = ce_v.second;
            if(result == -1) {
                polled_successfully_from.insert(remote_id);
            } else if(result == -1) {
                failed_node_indexes.push_back(remote_id);
            }
        }
        util::polling_data.reset_waiting(tid);

        for(auto index : failed_node_indexes) {
            if(failure_upcall) {
                failure_upcall(index);
            }
        }
    }
}

void P2PConnectionManager::filter_to(const std::vector<node_id_t>& live_nodes_list) {
    std::vector<node_id_t> prev_nodes_list;
    for (const auto& e : p2p_connections ) {
        prev_nodes_list.push_back(e.first);
    }
    std::vector<node_id_t> departed;
    std::set_difference(prev_nodes_list.begin(), prev_nodes_list.end(),
                        live_nodes_list.begin(), live_nodes_list.end(),
                        std::back_inserter(departed));
    remove_connections(departed);
}
void P2PConnectionManager::debug_print() {
    // std::cout << "Members: " << std::endl;
    // for(const auto& [node_id, p2p_conn] : p2p_connections) {
    //     std::cout << node_id << " ";
    // }
    // std::cout << std::endl;

    // for(const auto& type : p2p_request_types) {
    //     std::cout << "P2PConnections: Request type " << type << std::endl;
    //     for(uint32_t node = 0; node < num_members; ++node) {
    //         std::cout << "Node " << node << std::endl;
    //         std::cout << "incoming seq_nums:";
    //         for(uint32_t i = 0; i < request_params.window_sizes[type]; ++i) {
    //             uint64_t offset = request_params.max_msg_sizes[type] * (type * request_params.window_sizes[type] + i + 1) - sizeof(uint64_t);
    //             std::cout << " " << (uint64_t&)p2p_connections[node]->incoming_p2p_buffer[offset];
    //         }
    //         std::cout << std::endl
    //                   << "outgoing seq_nums:";
    //         for(uint32_t i = 0; i < request_params.window_sizes[type]; ++i) {
    //             uint64_t offset = request_params.max_msg_sizes[type] * (type * request_params.window_sizes[type] + i + 1) - sizeof(uint64_t);
    //             std::cout << " " << (uint64_t&)p2p_connections[node]->outgoing_p2p_buffer[offset];
    //         }
    //         std::cout << std::endl;
    //     }
    // }
}
}  // namespace sst
<commit_msg>fixed failure detection so that it checks every 1 second regardless of num_rdma_writes<commit_after>#include <cassert>
#include <cstring>
#include <sstream>
#include <sys/time.h>
#include <unordered_set>

#include <derecho/conf/conf.hpp>
#include <derecho/core/detail/p2p_connection_manager.hpp>
#include <derecho/sst/detail/poll_utils.hpp>

namespace sst {
P2PConnectionManager::P2PConnectionManager(const P2PParams params)
        : my_node_id(params.my_node_id),
          failure_upcall(params.failure_upcall) {

    // HARD-CODED. Adding another request type will break this

    request_params.window_sizes[P2P_REPLY] = params.p2p_window_size;
    request_params.window_sizes[P2P_REQUEST] = params.p2p_window_size;
    request_params.window_sizes[RPC_REPLY] = params.rpc_window_size;
    request_params.max_msg_sizes[P2P_REPLY] = params.max_p2p_reply_size;
    request_params.max_msg_sizes[P2P_REQUEST] = params.max_p2p_request_size;
    request_params.max_msg_sizes[RPC_REPLY] = params.max_rpc_reply_size;

    p2p_buf_size = 0;
    for(uint8_t i = 0; i < num_request_types; ++i) {
        request_params.offsets[i] = p2p_buf_size;
        p2p_buf_size += request_params.window_sizes[i] * request_params.max_msg_sizes[i];
    }
    p2p_buf_size += sizeof(bool);

    p2p_connections[my_node_id] = std::make_unique<P2PConnection>(my_node_id, my_node_id, p2p_buf_size, request_params);

    // external client doesn't need failure checking
    if (!params.is_external) {
        timeout_thread = std::thread(&P2PConnectionManager::check_failures_loop, this);
    }
}

P2PConnectionManager::~P2PConnectionManager() {
    shutdown_failures_thread();
}

void P2PConnectionManager::add_connections(const std::vector<node_id_t>& node_ids) {
    std::lock_guard<std::mutex> lock(connections_mutex);
    for (const node_id_t remote_id : node_ids) {
	if (p2p_connections.find(remote_id) == p2p_connections.end()) {
	    p2p_connections.emplace(remote_id, std::make_unique<P2PConnection>(my_node_id, remote_id, p2p_buf_size, request_params));
    	}
    }
}

void P2PConnectionManager::remove_connections(const std::vector<node_id_t>& node_ids) {
    std::lock_guard<std::mutex> lock(connections_mutex);
    for(const node_id_t remote_id : node_ids) {
        p2p_connections.erase(remote_id);
    }
}

void P2PConnectionManager::shutdown_failures_thread() {
    thread_shutdown = true;
    if(timeout_thread.joinable()) {
        timeout_thread.join();
    }
}

uint64_t P2PConnectionManager::get_max_p2p_reply_size() {
    return request_params.max_msg_sizes[P2P_REPLY] - sizeof(uint64_t);
}

void P2PConnectionManager::update_incoming_seq_num() {
    p2p_connections[last_node_id]->update_incoming_seq_num();
}

// check if there's a new request from any node
std::optional<std::pair<node_id_t, char*>> P2PConnectionManager::probe_all() {
    for(const auto& [node_id, p2p_conn] : p2p_connections) {
        auto buf = p2p_conn->probe();
        if(buf && buf[0]) {
            last_node_id = node_id;
            return std::pair<node_id_t, char*>(node_id, buf);
        } else if(buf) {
            // this means that we have a null reply
            // we don't need to process it, but we still want to increment the seq num
            p2p_conn->update_incoming_seq_num();
        }
    }
    return {};
}

char* P2PConnectionManager::get_sendbuffer_ptr(node_id_t node_id, REQUEST_TYPE type) {
    return p2p_connections.at(node_id)->get_sendbuffer_ptr(type);
}

void P2PConnectionManager::send(node_id_t node_id) {
    p2p_connections.at(node_id)->send();
    if(node_id != my_node_id) {
        p2p_connections.at(node_id)->num_rdma_writes++;
    }
}

void P2PConnectionManager::check_failures_loop() {
    pthread_setname_np(pthread_self(), "p2p_timeout");

    uint32_t heartbeat_ms = derecho::getConfUInt32(CONF_DERECHO_HEARTBEAT_MS);
    const auto tid = std::this_thread::get_id();
    // get id first
    uint32_t ce_idx = util::polling_data.get_index(tid);

    uint16_t tick_count = 0;
    while(!thread_shutdown) {
        std::this_thread::sleep_for(std::chrono::milliseconds(heartbeat_ms));
        tick_count++;
        std::unordered_set<node_id_t> posted_write_to;

        util::polling_data.set_waiting(tid);
#ifdef USE_VERBS_API
        std::map<uint32_t, struct verbs_sender_ctxt> sctxt;
#else
        std::map<uint32_t, struct lf_sender_ctxt> sctxt;
#endif

        for(const auto& [node_id, p2p_conn] : p2p_connections) {
            // checks every second regardless of num_rdma_writes
            if (node_id == my_node_id || (p2p_conn->num_rdma_writes < 1000 && tick_count < 1000)) {
                continue;
            }
            p2p_conn->num_rdma_writes = 0;
            sctxt[node_id].remote_id = node_id;
            sctxt[node_id].ce_idx = ce_idx;

            p2p_conn->get_res()->post_remote_write_with_completion(&sctxt[node_id], p2p_buf_size - sizeof(bool), sizeof(bool));
            posted_write_to.insert(node_id);
        }
        if (tick_count >= 1000) {
            tick_count = 0;
        }

        // track which nodes respond successfully
        std::unordered_set<node_id_t> polled_successfully_from;
        std::vector<node_id_t> failed_node_indexes;

        /** Completion Queue poll timeout in millisec */
        const int MAX_POLL_CQ_TIMEOUT = 2000;
        unsigned long start_time_msec;
        unsigned long cur_time_msec;
        struct timeval cur_time;

        // wait for completion for a while before giving up of doing it ..
        gettimeofday(&cur_time, NULL);
        start_time_msec = (cur_time.tv_sec * 1000) + (cur_time.tv_usec / 1000);

        uint32_t num_completions = 0;
        while(num_completions < p2p_connections.size() - 1) {
            std::optional<std::pair<int32_t, int32_t>> ce;
            while(true) {
                // check if polling result is available
                ce = util::polling_data.get_completion_entry(tid);
                if(ce) {
                    break;
                }
                gettimeofday(&cur_time, NULL);
                cur_time_msec = (cur_time.tv_sec * 1000) + (cur_time.tv_usec / 1000);
                if((cur_time_msec - start_time_msec) >= MAX_POLL_CQ_TIMEOUT) {
                    break;
                }
            }
            // if waiting for a completion entry timed out
            if(!ce) {
                // mark all nodes that have not yet responded as failed
                for(const auto& pair : p2p_connections) {
                    const auto& node_id = pair.first;
                    if(posted_write_to.find(node_id) == posted_write_to.end()
                    || polled_successfully_from.find(node_id) != polled_successfully_from.end()) {
                        continue;
                    }
                    failed_node_indexes.push_back(node_id);
                }
                break;
            }
            num_completions++;

            auto ce_v = ce.value();
            int remote_id = ce_v.first;
            int result = ce_v.second;
            if(result == -1) {
                polled_successfully_from.insert(remote_id);
            } else if(result == -1) {
                failed_node_indexes.push_back(remote_id);
            }
        }
        util::polling_data.reset_waiting(tid);

        for(auto index : failed_node_indexes) {
            if(failure_upcall) {
                failure_upcall(index);
            }
        }
    }
}

void P2PConnectionManager::filter_to(const std::vector<node_id_t>& live_nodes_list) {
    std::vector<node_id_t> prev_nodes_list;
    for (const auto& e : p2p_connections ) {
        prev_nodes_list.push_back(e.first);
    }
    std::vector<node_id_t> departed;
    std::set_difference(prev_nodes_list.begin(), prev_nodes_list.end(),
                        live_nodes_list.begin(), live_nodes_list.end(),
                        std::back_inserter(departed));
    remove_connections(departed);
}
void P2PConnectionManager::debug_print() {
    // std::cout << "Members: " << std::endl;
    // for(const auto& [node_id, p2p_conn] : p2p_connections) {
    //     std::cout << node_id << " ";
    // }
    // std::cout << std::endl;

    // for(const auto& type : p2p_request_types) {
    //     std::cout << "P2PConnections: Request type " << type << std::endl;
    //     for(uint32_t node = 0; node < num_members; ++node) {
    //         std::cout << "Node " << node << std::endl;
    //         std::cout << "incoming seq_nums:";
    //         for(uint32_t i = 0; i < request_params.window_sizes[type]; ++i) {
    //             uint64_t offset = request_params.max_msg_sizes[type] * (type * request_params.window_sizes[type] + i + 1) - sizeof(uint64_t);
    //             std::cout << " " << (uint64_t&)p2p_connections[node]->incoming_p2p_buffer[offset];
    //         }
    //         std::cout << std::endl
    //                   << "outgoing seq_nums:";
    //         for(uint32_t i = 0; i < request_params.window_sizes[type]; ++i) {
    //             uint64_t offset = request_params.max_msg_sizes[type] * (type * request_params.window_sizes[type] + i + 1) - sizeof(uint64_t);
    //             std::cout << " " << (uint64_t&)p2p_connections[node]->outgoing_p2p_buffer[offset];
    //         }
    //         std::cout << std::endl;
    //     }
    // }
}
}  // namespace sst
<|endoftext|>


<commit_before>#include "multimediabuffer.hpp"

using namespace dash;
using namespace player;

MultimediaBuffer::MultimediaBuffer(unsigned int maxBufferedSeconds)
{
  this->maxBufferedSeconds= (double) maxBufferedSeconds;

  toBufferSegmentNumber = 0;
  toConsumeSegmentNumber = 0;
}

MultimediaBuffer::~MultimediaBuffer()
{
}

bool MultimediaBuffer::addToBuffer(unsigned int segmentNumber, const dash::mpd::IRepresentation* usedRepresentation)
{
  //check if we receive a segment with a too large number
  if(toBufferSegmentNumber < segmentNumber)
    return false;

  //fprintf(stderr, "toBufferSegmentNumber=%d < segmentNumber=%d\n",toBufferSegmentNumber,segmentNumber);

  //determine segment duration
  double duration = (double) usedRepresentation->GetSegmentList()->GetDuration();
  duration /= (double) usedRepresentation->GetSegmentList()->GetTimescale ();

  // Check if segment has depIds
  mtx.lock ();
  if(usedRepresentation->GetDependencyId ().size() > 0)
  {
    // if so find the correct map
    MBuffer::iterator it = buff.find (segmentNumber);
    if(it == buff.end ())
      return false;

    BufferRepresentationEntryMap map = it->second;

    for(std::vector<std::string>::const_iterator k = usedRepresentation->GetDependencyId ().begin ();
        k !=  usedRepresentation->GetDependencyId ().end (); k++)
    {
      //depId not found we can not add this layer
      if(map.find ((*k)) == map.end ())
      {
        //fprintf(stderr, "Could not find '%s' in map\n", (*k).c_str());
        mtx.unlock ();
        return false;
      }
    }
  }
  else
  {
    //check if segment with layer == 0 fits in buffer
    if(isFull(usedRepresentation->GetId (),duration))
    {
      mtx.unlock ();
      return false;
    }
  }

  // Add segment to buffer
  //fprintf(stderr, "Inserted something for Segment %d in Buffer\n", segmentNumber);

  MultimediaBuffer::BufferRepresentationEntry entry;
  entry.repId = usedRepresentation->GetId ();
  entry.segmentDuration = duration;
  entry.segmentNumber = segmentNumber;
  entry.depIds = usedRepresentation->GetDependencyId ();
  entry.bitrate_bit_s = usedRepresentation->GetBandwidth ();

  buff[segmentNumber][usedRepresentation->GetId ()] = entry;
  toBufferSegmentNumber++;
  mtx.unlock ();
  return true;
}

bool MultimediaBuffer::enoughSpaceInBuffer(unsigned int segmentNumber, const dash::mpd::IRepresentation* usedRepresentation)
{
  //determine segment duration
  double duration = (double) usedRepresentation->GetSegmentList()->GetDuration();
  duration /= (double) usedRepresentation->GetSegmentList()->GetTimescale ();

  if(isFull(usedRepresentation->GetId (),duration))
    return false;

  return true;
}

bool MultimediaBuffer::isFull(std::string repId, double additional_seconds)
{
  if(maxBufferedSeconds < additional_seconds+getBufferedSeconds(repId))
    return true;
  return false;
}

bool MultimediaBuffer::isEmpty()
{
  if(getBufferedSeconds() <= 0.0)
    return true;
  return false;
}

double MultimediaBuffer::getBufferedSeconds()
{
  double bufferSize = 0.0;

  for(MBuffer::iterator it = buff.begin (); it != buff.end (); ++it)
    bufferSize += it->second.begin()->second.segmentDuration;

  //fprintf(stderr, "BufferSize for lowestRep = %f\n", bufferSize);
  return bufferSize;
}

double MultimediaBuffer::getBufferedSeconds(std::string repId)
{
  double bufferSize = 0.0;
  for(MBuffer::iterator it = buff.begin (); it != buff.end (); ++it)
  {
    BufferRepresentationEntryMap::iterator k = it->second.find(repId);
    if(k != it->second.end())
    {
      bufferSize += k->second.segmentDuration;
    }
  }
  //fprintf(stderr, "BufferSize for rep[%s] = %f\n", repId.c_str (),bufferSize);
  return bufferSize;
}

unsigned int MultimediaBuffer::getHighestBufferedSegmentNr(std::string repId)
{
  //std::map should be orderd based on operator<, so iterate from the back
  for(MBuffer::reverse_iterator it = buff.rbegin (); it != buff.rend (); ++it)
  {
    BufferRepresentationEntryMap::iterator k = it->second.find(repId);
    if(k != it->second.end())
    {
      return k->second.segmentNumber;
    }
  }
  return 0;
}

MultimediaBuffer::BufferRepresentationEntry MultimediaBuffer::consumeFromBuffer()
{
  BufferRepresentationEntry entryConsumed;

  if(isEmpty())
    return entryConsumed;

  MBuffer::iterator it = buff.find (toConsumeSegmentNumber);
  if(it == buff.end ())
  {
    fprintf(stderr, "Could not find SegmentNumber. This should never happen\n");
    return entryConsumed;
  }

  mtx.lock ();
  entryConsumed = getHighestConsumableRepresentation(toConsumeSegmentNumber);
  buff.erase (it);
  toConsumeSegmentNumber++;
  mtx.unlock ();
  return entryConsumed;
}

MultimediaBuffer::BufferRepresentationEntry MultimediaBuffer::getHighestConsumableRepresentation(int segmentNumber)
{
  BufferRepresentationEntry consumableEntry;

  // find the correct entry map
  MBuffer::iterator it = buff.find (segmentNumber);
  if(it == buff.end ())
  {
    return consumableEntry;
  }

  BufferRepresentationEntryMap map = it->second;

  //find entry with most depIds.
  unsigned int most_depIds = 0;
  for(BufferRepresentationEntryMap::iterator k = map.begin (); k != map.end (); ++k)
  {
    if(most_depIds <= k->second.depIds.size())
    {
      consumableEntry = k->second;
      most_depIds = k->second.depIds.size();
    }
  }
  return consumableEntry;
}

double MultimediaBuffer::getBufferedPercentage()
{
  return getBufferedSeconds() / maxBufferedSeconds;
}

double MultimediaBuffer::getBufferedPercentage(std::string repId)
{
  return getBufferedSeconds (repId) / maxBufferedSeconds;
}

<commit_msg>fixed mutex usage.<commit_after>#include "multimediabuffer.hpp"

using namespace dash;
using namespace player;

MultimediaBuffer::MultimediaBuffer(unsigned int maxBufferedSeconds)
{
  this->maxBufferedSeconds= (double) maxBufferedSeconds;

  toBufferSegmentNumber = 0;
  toConsumeSegmentNumber = 0;
}

MultimediaBuffer::~MultimediaBuffer()
{
}

bool MultimediaBuffer::addToBuffer(unsigned int segmentNumber, const dash::mpd::IRepresentation* usedRepresentation)
{
  //check if we receive a segment with a too large number
  if(toBufferSegmentNumber < segmentNumber)
    return false;

  //fprintf(stderr, "toBufferSegmentNumber=%d < segmentNumber=%d\n",toBufferSegmentNumber,segmentNumber);

  //determine segment duration
  double duration = (double) usedRepresentation->GetSegmentList()->GetDuration();
  duration /= (double) usedRepresentation->GetSegmentList()->GetTimescale ();

  // Check if segment has depIds
  mtx.lock ();
  if(usedRepresentation->GetDependencyId ().size() > 0)
  {
    // if so find the correct map
    MBuffer::iterator it = buff.find (segmentNumber);
    if(it == buff.end ())
    {
      mtx.unlock();
      return false;
    }

    BufferRepresentationEntryMap map = it->second;

    for(std::vector<std::string>::const_iterator k = usedRepresentation->GetDependencyId ().begin ();
        k !=  usedRepresentation->GetDependencyId ().end (); k++)
    {
      //depId not found we can not add this layer
      if(map.find ((*k)) == map.end ())
      {
        //fprintf(stderr, "Could not find '%s' in map\n", (*k).c_str());
        mtx.unlock ();
        return false;
      }
    }
  }
  else
  {
    //check if segment with layer == 0 fits in buffer
    if(isFull(usedRepresentation->GetId (),duration))
    {
      mtx.unlock ();
      return false;
    }
  }

  // Add segment to buffer
  //fprintf(stderr, "Inserted something for Segment %d in Buffer\n", segmentNumber);

  MultimediaBuffer::BufferRepresentationEntry entry;
  entry.repId = usedRepresentation->GetId ();
  entry.segmentDuration = duration;
  entry.segmentNumber = segmentNumber;
  entry.depIds = usedRepresentation->GetDependencyId ();
  entry.bitrate_bit_s = usedRepresentation->GetBandwidth ();

  buff[segmentNumber][usedRepresentation->GetId ()] = entry;
  toBufferSegmentNumber++;
  mtx.unlock ();
  return true;
}

bool MultimediaBuffer::enoughSpaceInBuffer(unsigned int segmentNumber, const dash::mpd::IRepresentation* usedRepresentation)
{
  //determine segment duration
  double duration = (double) usedRepresentation->GetSegmentList()->GetDuration();
  duration /= (double) usedRepresentation->GetSegmentList()->GetTimescale ();

  if(isFull(usedRepresentation->GetId (),duration))
    return false;

  return true;
}

bool MultimediaBuffer::isFull(std::string repId, double additional_seconds)
{
  if(maxBufferedSeconds < additional_seconds+getBufferedSeconds(repId))
    return true;
  return false;
}

bool MultimediaBuffer::isEmpty()
{
  if(getBufferedSeconds() <= 0.0)
    return true;
  return false;
}

double MultimediaBuffer::getBufferedSeconds()
{
  double bufferSize = 0.0;

  for(MBuffer::iterator it = buff.begin (); it != buff.end (); ++it)
    bufferSize += it->second.begin()->second.segmentDuration;

  //fprintf(stderr, "BufferSize for lowestRep = %f\n", bufferSize);
  return bufferSize;
}

double MultimediaBuffer::getBufferedSeconds(std::string repId)
{
  double bufferSize = 0.0;
  for(MBuffer::iterator it = buff.begin (); it != buff.end (); ++it)
  {
    BufferRepresentationEntryMap::iterator k = it->second.find(repId);
    if(k != it->second.end())
    {
      bufferSize += k->second.segmentDuration;
    }
  }
  //fprintf(stderr, "BufferSize for rep[%s] = %f\n", repId.c_str (),bufferSize);
  return bufferSize;
}

unsigned int MultimediaBuffer::getHighestBufferedSegmentNr(std::string repId)
{
  //std::map should be orderd based on operator<, so iterate from the back
  for(MBuffer::reverse_iterator it = buff.rbegin (); it != buff.rend (); ++it)
  {
    BufferRepresentationEntryMap::iterator k = it->second.find(repId);
    if(k != it->second.end())
    {
      return k->second.segmentNumber;
    }
  }
  return 0;
}

MultimediaBuffer::BufferRepresentationEntry MultimediaBuffer::consumeFromBuffer()
{
  BufferRepresentationEntry entryConsumed;

  if(isEmpty())
    return entryConsumed;

  MBuffer::iterator it = buff.find (toConsumeSegmentNumber);
  if(it == buff.end ())
  {
    fprintf(stderr, "Could not find SegmentNumber. This should never happen\n");
    return entryConsumed;
  }

  mtx.lock ();
  entryConsumed = getHighestConsumableRepresentation(toConsumeSegmentNumber);
  buff.erase (it);
  toConsumeSegmentNumber++;
  mtx.unlock ();
  return entryConsumed;
}

MultimediaBuffer::BufferRepresentationEntry MultimediaBuffer::getHighestConsumableRepresentation(int segmentNumber)
{
  BufferRepresentationEntry consumableEntry;

  // find the correct entry map
  MBuffer::iterator it = buff.find (segmentNumber);
  if(it == buff.end ())
  {
    return consumableEntry;
  }

  BufferRepresentationEntryMap map = it->second;

  //find entry with most depIds.
  unsigned int most_depIds = 0;
  for(BufferRepresentationEntryMap::iterator k = map.begin (); k != map.end (); ++k)
  {
    if(most_depIds <= k->second.depIds.size())
    {
      consumableEntry = k->second;
      most_depIds = k->second.depIds.size();
    }
  }
  return consumableEntry;
}

double MultimediaBuffer::getBufferedPercentage()
{
  return getBufferedSeconds() / maxBufferedSeconds;
}

double MultimediaBuffer::getBufferedPercentage(std::string repId)
{
  return getBufferedSeconds (repId) / maxBufferedSeconds;
}

<|endoftext|>