<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.
 *
 ***************************************************************/

#include "condor_common.h"

/*
** free_fs_blocks: reports the number of kbytes free for the filesystem where
** given filename resides.
*/

#include "sysapi.h"
#include "sysapi_externs.h"
#include "my_popen.h"

/* static function declarations */
static int reserve_for_afs_cache(void);
static int reserve_for_fs(void);

/* the code starts here */

#if defined(WIN32)

#include <limits.h>

long long
sysapi_disk_space_raw(const char *filename)
{
	ULARGE_INTEGER FreeBytesAvailableToCaller, TotalNumberOfBytes, TotalNumberOfFreeBytes;
	unsigned int t_hi, t_lo, temp;
	const unsigned int lowest_ten_mask = 0x000003ff;

	t_hi = t_lo = temp = 0;
	sysapi_internal_reconfig();

	if (GetDiskFreeSpaceEx(filename, &FreeBytesAvailableToCaller, &TotalNumberOfBytes,
		&TotalNumberOfFreeBytes) == 0) {
		return -1;
	} else {
#if 1
		return FreeBytesAvailableToCaller.QuadPart;
#else
		// we have to shift everything down 10 bits since we report the number
		// of kbytes free. There's a HighPart and a LowPart, so it gets a little ugly.

		// first shift the low part (divide by 1024 to get it into kbytes)
		t_lo = FreeBytesAvailableToCaller.LowPart;
		t_lo = t_lo >> 10;
		// now grab the lowest 10 bits in the high part
		t_hi = FreeBytesAvailableToCaller.HighPart;
		temp = lowest_ten_mask & t_hi;
		// shift the high part 10 bits to get it into kbytes
		t_hi = t_hi >> 10;

		// shift the lowest 10 bits from the high part up to the
		// highest 10 bits, and stick them into the low part
		temp = temp << 22;
		t_lo |= temp;

		if (t_hi > 0) {
			return INT_MAX;
		} else {
			return (int)t_lo;
		}
#endif
	}
}

#else

#include "condor_debug.h"

/* Can't include condor_config.h since it depends on classads which is
   only C++.  -Derek 6/25/98 */
extern char* param();

#define FS_PROGRAM "/usr/afsws/bin/fs"
#define FS_COMMAND "getcacheparms"
#define FS_OUTPUT_FORMAT "\nAFS using %d of the cache's available %d"

#endif

/*
  How much disk space we need to reserve for the AFS cache.  Answer is
  in kilobytes.
*/
static int
reserve_for_afs_cache()
{
#ifdef WIN32
	return 0;
#else
	int		answer;
	FILE	*fp;
	const char	*args[] = {FS_PROGRAM, FS_COMMAND, NULL};
	int		cache_size, cache_in_use;
	int		do_it;

	/* See if we're configured to deal with an AFS cache */
	do_it = _sysapi_reserve_afs_cache;

		/* If we're not configured to deal with AFS cache, just return 0 */
	if( !do_it ) {
		return 0;
	}

		/* Run an AFS utility program to learn how big the cache is and
		   how much is in use. */
	dprintf( D_FULLDEBUG, "Checking AFS cache parameters\n" );
	fp = my_popenv( args, "r", FALSE );
	if( !fp ) {
		return 0;
	}
	if (fscanf( fp, FS_OUTPUT_FORMAT, &cache_in_use, &cache_size ) != 2) {
		dprintf( D_ALWAYS, "Failed to parse AFS cache parameters, assuming no cache\n" );
		cache_size = 0;
		cache_in_use = 0;
	}
	my_pclose( fp );
	dprintf( D_FULLDEBUG, "cache_in_use = %d, cache_size = %d\n",
		cache_in_use,
		cache_size
	);
	answer = cache_size - cache_in_use;

		/* The cache may be temporarily over size, in this case AFS will
		   clean up itself, so we don't have to allow for that. */
	if( answer < 0 ) {
		answer = 0;
	}

	dprintf( D_FULLDEBUG, "Reserving %d kbytes for AFS cache\n", answer );
	return answer;
#endif
}

/*
  How much disk space we need to reserve for the regular file system.
  Answer is in kilobytes.
*/
static int
reserve_for_fs()
{
	/* XXX make cleaner */
	int	answer = -1;

	if( answer < 0 ) {
		answer = _sysapi_reserve_disk;
		if( answer < 0 ) {
			answer = 0;
		}
	}

	answer = _sysapi_reserve_disk;
	return answer;
}

#if defined(__STDC__)
long long sysapi_disk_space_raw( const char *filename);
#else
long long sysapi_disk_space_raw();
#endif

#if defined(LINUX) || defined(AIX) || defined(HPUX) || defined(Solaris) || defined(Darwin) || defined(CONDOR_FREEBSD)

#include <limits.h>

#if defined(AIX)
#include <sys/statfs.h>
#elif defined(Solaris)
#include <sys/statvfs.h>
#endif

long long sysapi_disk_space_raw(const char * filename)
{
#if defined(Solaris)
	struct statvfs statfsbuf;
#else
	struct statfs statfsbuf;
#endif
#if 1
	long long free_kbytes;
	double kbytes_per_block;
#else
	double free_kbytes;
	float kbytes_per_block;
#endif

	sysapi_internal_reconfig();

#if defined(Solaris)
	if(statvfs(filename, &statfsbuf) < 0) {
#elif defined(AIX)
	if(statfs((char *)filename, &statfsbuf) < 0) {
#else
	if(statfs(filename, &statfsbuf) < 0) {
#endif
		if (errno != EOVERFLOW) {
			dprintf(D_ALWAYS, "sysapi_disk_space_raw: statfs(%s,%p) failed\n",
													filename, &statfsbuf );
			dprintf(D_ALWAYS, "errno = %d\n", errno );

			return(0);
		}

		// if we get here, it means that statfs failed because
		// there are more free blocks than can be represented
		// in a long.  Let's lie and make it INT_MAX - 1.

		dprintf(D_FULLDEBUG, "sysapi_disk_space_raw: statfs overflowed, setting to %d\n", (INT_MAX - 1));
		statfsbuf.f_bavail = (INT_MAX - 1);
		statfsbuf.f_bsize = 1024; // this isn't set if result < 0, guess
	}

	/* Convert to kbyte blocks: available blks * blksize / 1k bytes. */
	/* overflow problem fixed by using doubles to hold result -
		Keller 05/17/99 */

#if defined(Solaris)
		/* On Solaris, we need to use f_frsize, the "fundamental
		   filesystem block size", not f_bsize, the "preferred file
		   system block size".  3/25/98  Derek Wright */
	kbytes_per_block = ( (unsigned long)statfsbuf.f_frsize / 1024.0 );
#else
	kbytes_per_block = ( (unsigned long)statfsbuf.f_bsize / 1024.0 );
#endif

#if 1
	free_kbytes = (long long)(statfsbuf.f_bavail * kbytes_per_block);
#else
	free_kbytes = (double)statfsbuf.f_bavail * (double)kbytes_per_block;
	if(free_kbytes > INT_MAX) {
		dprintf( D_ALWAYS, "sysapi_disk_space_raw: Free disk space kbytes overflow, capping to INT_MAX\n");
		return(INT_MAX);
	}
#endif

	return free_kbytes;
}
#endif

/*
  Return number of kbytes condor may play with in the named file
  system.  System administrators may reserve space which condor should
  leave alone.  This could be either a static amount of space, or an
  amount of space based on the current size of the AFS cache (or
  both).

  Note: This code assumes that if we have an AFS cache, that cache is
  on the filesystem we are asking about.  This is not true in general,
  but it is the case at the developer's home site.  A more correct
  implementation would check whether the filesystem being asked about
  is the one containing the cache.  This is messy to do if the
  filesystem name we are given isn't a full pathname, e.g.
  sysapi_disk_space("."), which is why it isn't implemented here. -- mike

*/
long long
sysapi_disk_space(const char *filename)
{
	long long answer;

	sysapi_internal_reconfig();

	answer =  sysapi_disk_space_raw(filename)
			- reserve_for_afs_cache()
			- reserve_for_fs();
	return answer < 0 ? 0 : answer;

}

<commit_msg>fix off by 1024 in reporting disk space on Windows. #4638 ===VersionHistory:Pending===<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.
 *
 ***************************************************************/

#include "condor_common.h"

/*
** free_fs_blocks: reports the number of kbytes free for the filesystem where
** given filename resides.
*/

#include "sysapi.h"
#include "sysapi_externs.h"
#include "my_popen.h"

/* static function declarations */
static int reserve_for_afs_cache(void);
static int reserve_for_fs(void);

/* the code starts here */

#if defined(WIN32)

#include <limits.h>

long long
sysapi_disk_space_raw(const char *filename)
{
	ULARGE_INTEGER FreeBytesAvailableToCaller, TotalNumberOfBytes, TotalNumberOfFreeBytes;
	unsigned int t_hi, t_lo, temp;
	const unsigned int lowest_ten_mask = 0x000003ff;

	t_hi = t_lo = temp = 0;
	sysapi_internal_reconfig();

	if (GetDiskFreeSpaceEx(filename, &FreeBytesAvailableToCaller, &TotalNumberOfBytes,
		&TotalNumberOfFreeBytes) == 0) {
		return -1;
	} else {
		return FreeBytesAvailableToCaller.QuadPart / 1024;
	}
}

#else

#include "condor_debug.h"

/* Can't include condor_config.h since it depends on classads which is
   only C++.  -Derek 6/25/98 */
extern char* param();

#define FS_PROGRAM "/usr/afsws/bin/fs"
#define FS_COMMAND "getcacheparms"
#define FS_OUTPUT_FORMAT "\nAFS using %d of the cache's available %d"

#endif

/*
  How much disk space we need to reserve for the AFS cache.  Answer is
  in kilobytes.
*/
static int
reserve_for_afs_cache()
{
#ifdef WIN32
	return 0;
#else
	int		answer;
	FILE	*fp;
	const char	*args[] = {FS_PROGRAM, FS_COMMAND, NULL};
	int		cache_size, cache_in_use;
	int		do_it;

	/* See if we're configured to deal with an AFS cache */
	do_it = _sysapi_reserve_afs_cache;

		/* If we're not configured to deal with AFS cache, just return 0 */
	if( !do_it ) {
		return 0;
	}

		/* Run an AFS utility program to learn how big the cache is and
		   how much is in use. */
	dprintf( D_FULLDEBUG, "Checking AFS cache parameters\n" );
	fp = my_popenv( args, "r", FALSE );
	if( !fp ) {
		return 0;
	}
	if (fscanf( fp, FS_OUTPUT_FORMAT, &cache_in_use, &cache_size ) != 2) {
		dprintf( D_ALWAYS, "Failed to parse AFS cache parameters, assuming no cache\n" );
		cache_size = 0;
		cache_in_use = 0;
	}
	my_pclose( fp );
	dprintf( D_FULLDEBUG, "cache_in_use = %d, cache_size = %d\n",
		cache_in_use,
		cache_size
	);
	answer = cache_size - cache_in_use;

		/* The cache may be temporarily over size, in this case AFS will
		   clean up itself, so we don't have to allow for that. */
	if( answer < 0 ) {
		answer = 0;
	}

	dprintf( D_FULLDEBUG, "Reserving %d kbytes for AFS cache\n", answer );
	return answer;
#endif
}

/*
  How much disk space we need to reserve for the regular file system.
  Answer is in kilobytes.
*/
static int
reserve_for_fs()
{
	/* XXX make cleaner */
	int	answer = -1;

	if( answer < 0 ) {
		answer = _sysapi_reserve_disk;
		if( answer < 0 ) {
			answer = 0;
		}
	}

	answer = _sysapi_reserve_disk;
	return answer;
}

#if defined(__STDC__)
long long sysapi_disk_space_raw( const char *filename);
#else
long long sysapi_disk_space_raw();
#endif

#if defined(LINUX) || defined(AIX) || defined(HPUX) || defined(Solaris) || defined(Darwin) || defined(CONDOR_FREEBSD)

#include <limits.h>

#if defined(AIX)
#include <sys/statfs.h>
#elif defined(Solaris)
#include <sys/statvfs.h>
#endif

long long sysapi_disk_space_raw(const char * filename)
{
#if defined(Solaris)
	struct statvfs statfsbuf;
#else
	struct statfs statfsbuf;
#endif
	long long free_kbytes;
	double kbytes_per_block;

	sysapi_internal_reconfig();

#if defined(Solaris)
	if(statvfs(filename, &statfsbuf) < 0) {
#elif defined(AIX)
	if(statfs((char *)filename, &statfsbuf) < 0) {
#else
	if(statfs(filename, &statfsbuf) < 0) {
#endif
		if (errno != EOVERFLOW) {
			dprintf(D_ALWAYS, "sysapi_disk_space_raw: statfs(%s,%p) failed\n",
													filename, &statfsbuf );
			dprintf(D_ALWAYS, "errno = %d\n", errno );

			return(0);
		}

		// if we get here, it means that statfs failed because
		// there are more free blocks than can be represented
		// in a long.  Let's lie and make it INT_MAX - 1.

		dprintf(D_FULLDEBUG, "sysapi_disk_space_raw: statfs overflowed, setting to %d\n", (INT_MAX - 1));
		statfsbuf.f_bavail = (INT_MAX - 1);
		statfsbuf.f_bsize = 1024; // this isn't set if result < 0, guess
	}

	/* Convert to kbyte blocks: available blks * blksize / 1k bytes. */
	/* overflow problem fixed by using doubles to hold result -
		Keller 05/17/99 */

#if defined(Solaris)
		/* On Solaris, we need to use f_frsize, the "fundamental
		   filesystem block size", not f_bsize, the "preferred file
		   system block size".  3/25/98  Derek Wright */
	kbytes_per_block = ( (unsigned long)statfsbuf.f_frsize / 1024.0 );
#else
	kbytes_per_block = ( (unsigned long)statfsbuf.f_bsize / 1024.0 );
#endif

	free_kbytes = (long long)(statfsbuf.f_bavail * kbytes_per_block);

	return free_kbytes;
}
#endif

/*
  Return number of kbytes condor may play with in the named file
  system.  System administrators may reserve space which condor should
  leave alone.  This could be either a static amount of space, or an
  amount of space based on the current size of the AFS cache (or
  both).

  Note: This code assumes that if we have an AFS cache, that cache is
  on the filesystem we are asking about.  This is not true in general,
  but it is the case at the developer's home site.  A more correct
  implementation would check whether the filesystem being asked about
  is the one containing the cache.  This is messy to do if the
  filesystem name we are given isn't a full pathname, e.g.
  sysapi_disk_space("."), which is why it isn't implemented here. -- mike

*/
long long
sysapi_disk_space(const char *filename)
{
	long long answer;

	sysapi_internal_reconfig();

	answer =  sysapi_disk_space_raw(filename)
			- reserve_for_afs_cache()
			- reserve_for_fs();
	return answer < 0 ? 0 : answer;

}

<|endoftext|>


<commit_before> /*************************************************************************
 *
 *  $RCSfile: EApi.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: hr $ $Date: 2005-06-09 14:09:20 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an AS IS basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Michael Meeks, Jayant Madavi
 *
 *
 ************************************************************************/

#include <rtl/ustring.hxx>
#include <osl/module.h>
#include <stdio.h>
#define _EVOLUTION_ALREADY_DEFINED_ 1
#ifndef _CONNECTIVITY_EVOAB_EVOLUTION_API_HXX_
#include "EApi.h"
#endif
static char *eBookLibNames[] = {
    "libebook.so.8",    // evolution-2.0
    "libebook-1.2.so.3" // evolution-2.2
    // FIXME: ask JPR about ABI compatibility going forwards
    // "libebook-1.3.so.0",
    // "libebook-1.4.so.0",
    // "libebook-1.5.so.0"
};

typedef void (*SymbolFunc) (void);

#define SYM_MAP(a) { #a, (SymbolFunc *)&a }
    static struct {
    const char *sym_name;
    SymbolFunc *ref_value;
    } aApiMap[] = {
    SYM_MAP( e_contact_get_type ),
    SYM_MAP( e_contact_field_id ),
    SYM_MAP( e_source_peek_name ),
    SYM_MAP( e_source_get_property ),
    SYM_MAP( e_source_list_peek_groups ),
    SYM_MAP( e_source_group_peek_sources ),
    SYM_MAP( e_book_new ),
    SYM_MAP( e_book_open ),
    SYM_MAP( e_book_get_uri ),
    SYM_MAP( e_book_get_source ),
    SYM_MAP( e_book_get_addressbooks ),
    SYM_MAP( e_book_get_contacts ),
    SYM_MAP( e_book_authenticate_user ),
    SYM_MAP( e_book_query_field_test ),
    SYM_MAP( e_book_query_and ),
    SYM_MAP( e_book_query_or ),
    SYM_MAP( e_book_query_not ),
    SYM_MAP( e_book_query_unref ),
    SYM_MAP( e_book_query_to_string ),
    SYM_MAP( e_book_query_field_exists ),
    SYM_MAP( e_source_group_peek_base_uri)
    };
#undef SYM_MAP

static bool
tryLink( oslModule &aModule, const char *pName )
{
    for( guint i = 0; i < G_N_ELEMENTS( aApiMap ); i++ )
    {
    SymbolFunc aMethod;
    aMethod = (SymbolFunc) osl_getSymbol
        ( aModule, rtl::OUString::createFromAscii ( aApiMap[ i ].sym_name ).pData );
    if( !aMethod )
    {
        fprintf( stderr, "Warning: missing symbol '%s' in '%s'",
             aApiMap[ i ].sym_name, pName );
        return false;
    }
    * aApiMap[ i ].ref_value = aMethod;
    }
    return true;
}

bool EApiInit()
{
    oslModule aModule;

    for( guint j = 0; j < G_N_ELEMENTS( eBookLibNames ); j++ )
    {
    aModule = osl_loadModule( rtl::OUString::createFromAscii
                  ( eBookLibNames[ j ] ).pData,
                  SAL_LOADMODULE_DEFAULT );
    if( aModule)
    {
        if ( tryLink( aModule, eBookLibNames[ j ] ) )
        return true;
        osl_unloadModule( aModule );
    }
    }
    fprintf( stderr, "Can find no compliant libebook client libraries\n" );
    return false;
}

#if 0

  Test code - enable &
 *
 * Compile with ( after source LinuxIntelEnv.Set.sh )
   gcc $SOLARDEF -I $SOLARSRC/sal/inc -I $SOLARSRC/sal/unxlngi4.pro/inc \
     -I. `pkg-config --cflags --libs gobject-2.0` \
     -L $SOLARSRC/sal/unxlngi4.pro/lib -luno_sal -lstdc++ EApi.cxx

int main( int argc, char **argv)
{
    return EApiInit();
}

#endif

<commit_msg>INTEGRATION: CWS ooo19126 (1.2.40); FILE MERGED 2005/09/05 17:23:37 rt 1.2.40.1: #i54170# Change license header: remove SISSL<commit_after> /*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: EApi.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 05:48:53 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <rtl/ustring.hxx>
#include <osl/module.h>
#include <stdio.h>
#define _EVOLUTION_ALREADY_DEFINED_ 1
#ifndef _CONNECTIVITY_EVOAB_EVOLUTION_API_HXX_
#include "EApi.h"
#endif
static char *eBookLibNames[] = {
    "libebook.so.8",    // evolution-2.0
    "libebook-1.2.so.3" // evolution-2.2
    // FIXME: ask JPR about ABI compatibility going forwards
    // "libebook-1.3.so.0",
    // "libebook-1.4.so.0",
    // "libebook-1.5.so.0"
};

typedef void (*SymbolFunc) (void);

#define SYM_MAP(a) { #a, (SymbolFunc *)&a }
    static struct {
    const char *sym_name;
    SymbolFunc *ref_value;
    } aApiMap[] = {
    SYM_MAP( e_contact_get_type ),
    SYM_MAP( e_contact_field_id ),
    SYM_MAP( e_source_peek_name ),
    SYM_MAP( e_source_get_property ),
    SYM_MAP( e_source_list_peek_groups ),
    SYM_MAP( e_source_group_peek_sources ),
    SYM_MAP( e_book_new ),
    SYM_MAP( e_book_open ),
    SYM_MAP( e_book_get_uri ),
    SYM_MAP( e_book_get_source ),
    SYM_MAP( e_book_get_addressbooks ),
    SYM_MAP( e_book_get_contacts ),
    SYM_MAP( e_book_authenticate_user ),
    SYM_MAP( e_book_query_field_test ),
    SYM_MAP( e_book_query_and ),
    SYM_MAP( e_book_query_or ),
    SYM_MAP( e_book_query_not ),
    SYM_MAP( e_book_query_unref ),
    SYM_MAP( e_book_query_to_string ),
    SYM_MAP( e_book_query_field_exists ),
    SYM_MAP( e_source_group_peek_base_uri)
    };
#undef SYM_MAP

static bool
tryLink( oslModule &aModule, const char *pName )
{
    for( guint i = 0; i < G_N_ELEMENTS( aApiMap ); i++ )
    {
    SymbolFunc aMethod;
    aMethod = (SymbolFunc) osl_getSymbol
        ( aModule, rtl::OUString::createFromAscii ( aApiMap[ i ].sym_name ).pData );
    if( !aMethod )
    {
        fprintf( stderr, "Warning: missing symbol '%s' in '%s'",
             aApiMap[ i ].sym_name, pName );
        return false;
    }
    * aApiMap[ i ].ref_value = aMethod;
    }
    return true;
}

bool EApiInit()
{
    oslModule aModule;

    for( guint j = 0; j < G_N_ELEMENTS( eBookLibNames ); j++ )
    {
    aModule = osl_loadModule( rtl::OUString::createFromAscii
                  ( eBookLibNames[ j ] ).pData,
                  SAL_LOADMODULE_DEFAULT );
    if( aModule)
    {
        if ( tryLink( aModule, eBookLibNames[ j ] ) )
        return true;
        osl_unloadModule( aModule );
    }
    }
    fprintf( stderr, "Can find no compliant libebook client libraries\n" );
    return false;
}

#if 0

  Test code - enable &
 *
 * Compile with ( after source LinuxIntelEnv.Set.sh )
   gcc $SOLARDEF -I $SOLARSRC/sal/inc -I $SOLARSRC/sal/unxlngi4.pro/inc \
     -I. `pkg-config --cflags --libs gobject-2.0` \
     -L $SOLARSRC/sal/unxlngi4.pro/lib -luno_sal -lstdc++ EApi.cxx

int main( int argc, char **argv)
{
    return EApiInit();
}

#endif

<|endoftext|>


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

#include <miopen/conv/invokers/mlir_impl_gemm.hpp>

#include <miopen/conv/data_invoke_params.hpp>
#include <miopen/conv/wrw_invoke_params.hpp>
#include <miopen/algorithm.hpp>
#include <miopen/handle.hpp>
#include <miopen/tensor_ops.hpp>

#include <Miir.h>

#include <boost/any.hpp>
#include <boost/range/adaptors.hpp>

namespace miopen {
namespace conv {

namespace {
struct MlirConvArgs
{
    StridedMemRef5D filter;
    StridedMemRef5D input;
    StridedMemRef5D output;
};

// Rearrange strides correctly
// In MLIR: the layout, sizes and strides are coherent. The layout information is not
// embedded into the permutation of strides.
// - For NCHW, sizes = {N, C, H, W}; strides = {C*H*W, H*W, W, 1}
// - For NHWC, sizes = {N, H, W, C}; strides = {C*H*W, W*C, C, 1}

// In MIOpen however, size and strides are not aligned. Permutation of the strides are used to
// infer actual layout
// - For NCHW, sizes = {N, C, H, W}; strides = {C*H*W, H*W, W, 1}
// - For NHWC, sizes = {N, C, H, W}; strides = {C*H*W, 1, W*C, C}
void PermuteDimsStrides(std::vector<size_t>& dims, std::vector<size_t>& strides)
{
    auto sorted_dims    = dims;
    auto sorted_strides = strides;
    auto p              = TensorDescriptor::find_permutation(dims, strides);
    std::transform(p.begin(), p.end(), sorted_dims.begin(), [&](auto i) { return dims[i]; });
    std::transform(p.begin(), p.end(), sorted_strides.begin(), [&](auto i) { return strides[i]; });
    dims    = sorted_dims;
    strides = sorted_strides;
};

void InsertGToDimsStrides(const std::string& layout,
                          char dim,
                          int group_count,
                          std::vector<size_t>& dims,
                          std::vector<size_t>& strides)
{
    std::size_t index = layout.find(dim);
    if(index == std::string::npos)
        MIOPEN_THROW("Failed to find channel in the layout");

    // For dimensions,
    //    Insert an additional dimension g before channel
    //    Amend the channel size to be channel_size / group_count
    dims[index] /= group_count;
    dims.insert(dims.begin() + index, group_count);

    // For strides,
    //   The channel stride remain the same
    //   Insert an additional group stride to be channel_stride * new_channel_size
    strides.insert(strides.begin() + index, strides[index] * dims[index + 1]);
}

void ComputeMlirDimsStrides(const conv::ProblemDescription& conv_problem,
                            std::vector<size_t>& in_dims,
                            std::vector<size_t>& in_strides,
                            std::vector<size_t>& weights_dims,
                            std::vector<size_t>& weights_strides,
                            std::vector<size_t>& out_dims,
                            std::vector<size_t>& out_strides)
{
    auto group_count = conv_problem.GetGroupCount();

    TensorDescriptor in;
    if(conv_problem.GetDirection() == conv::Direction::Forward)
        in = conv_problem.GetIn();
    else
        in = conv_problem.GetOut();

    in_dims    = in.GetLengths();
    in_strides = in.GetStrides();
    PermuteDimsStrides(in_dims, in_strides);
    // Add a virtual group dimension before input channel.
    InsertGToDimsStrides(in.GetLayout("NCHW"), 'C', group_count, in_dims, in_strides);

    // Add a virtual group dimension before output channel.
    const TensorDescriptor& weights = conv_problem.GetWeights();
    weights_dims                    = weights.GetLengths();
    weights_strides                 = weights.GetStrides();
    PermuteDimsStrides(weights_dims, weights_strides);
    InsertGToDimsStrides(
        weights.GetLayout("NCHW"), 'N', group_count, weights_dims, weights_strides);

    TensorDescriptor out;
    if(conv_problem.GetDirection() == conv::Direction::Forward)
        out = conv_problem.GetOut();
    else
        out = conv_problem.GetIn();

    out_dims    = out.GetLengths();
    out_strides = out.GetStrides();
    PermuteDimsStrides(out_dims, out_strides);
    // Add a virtual group dimension before output channel.
    InsertGToDimsStrides(out.GetLayout("NCHW"), 'C', group_count, out_dims, out_strides);
}

MlirConvArgs MakeMlirConvArgs(const std::vector<size_t>& in_dims,
                              const std::vector<size_t>& in_strides,
                              const std::vector<size_t>& weights_dims,
                              const std::vector<size_t>& weights_strides,
                              const std::vector<size_t>& out_dims,
                              const std::vector<size_t>& out_strides)
{
    auto initDimStrides = [](const std::vector<size_t>& dims,
                             const std::vector<size_t>& strides,
                             StridedMemRef5D& target) {
        std::copy(dims.cbegin(), dims.cend(), &target.sizes[0]);
        std::copy(strides.cbegin(), strides.cend(), &target.strides[0]);
    };

    StridedMemRef5D filter{nullptr, nullptr, 0, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}};
    initDimStrides(weights_dims, weights_strides, filter);
    StridedMemRef5D input{nullptr, nullptr, 0, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}};
    initDimStrides(in_dims, in_strides, input);
    StridedMemRef5D output{nullptr, nullptr, 0, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}};
    initDimStrides(out_dims, out_strides, output);

    return {filter, input, output};
}

void SetMlirConvArgsPtr(ConstData_t in, ConstData_t out, ConstData_t w, MlirConvArgs& args)
{
    void* filter = nullptr;
    void* input  = nullptr;
    void* output = nullptr;
#if MIOPEN_BACKEND_OPENCL
    clGetMemObjectInfo(w, CL_MEM_HOST_PTR, sizeof(filter), &filter, nullptr);
    clGetMemObjectInfo(in, CL_MEM_HOST_PTR, sizeof(input), &input, nullptr);
    clGetMemObjectInfo(out, CL_MEM_HOST_PTR, sizeof(output), &output, nullptr);
#elif MIOPEN_BACKEND_HIP
    // NOLINTNEXTLINE (cppcoreguidelines-pro-type-const-cast)
    filter = const_cast<void*>(w);
    // NOLINTNEXTLINE (cppcoreguidelines-pro-type-const-cast)
    input = const_cast<void*>(in);
    // NOLINTNEXTLINE (cppcoreguidelines-pro-type-const-cast)
    output = const_cast<void*>(out);
#endif

    if((filter == nullptr) || (input == nullptr) || (output == nullptr))
        MIOPEN_THROW("Invalid device pointers");

    args.filter.basePtr = filter;
    args.filter.data    = filter;
    args.input.basePtr  = input;
    args.input.data     = input;
    args.output.basePtr = output;
    args.output.data    = output;
}
} // Anonymous namespace

InvokerFactory MakeMlirFwdInvokerFactory(const ConvolutionContext& ctx)
{
    assert((ctx.direction.IsForward()));

    std::vector<size_t> in_dims, in_strides;
    std::vector<size_t> weights_dims, weights_strides;
    std::vector<size_t> out_dims, out_strides;
    ComputeMlirDimsStrides(ctx.conv_problem,
                           in_dims,
                           in_strides,
                           weights_dims,
                           weights_strides,
                           out_dims,
                           out_strides);

    MlirConvArgs args =
        MakeMlirConvArgs(in_dims, in_strides, weights_dims, weights_strides, out_dims, out_strides);

    return [=](const std::vector<Kernel>& kernels) mutable {
        return [=](const Handle& handle, const AnyInvokeParams& primitive_parameters) mutable {
            const auto& forward_invoke_params =
                primitive_parameters.CastTo<conv::DataInvokeParams>();
            const auto& tensors = forward_invoke_params.tensors;

            SetMlirConvArgsPtr(tensors.in, tensors.out, tensors.w, args);
            handle.Run(kernels[0])(args);
        };
    };
}

InvokerFactory MakeMlirBwdInvokerFactory(const ConvolutionContext& ctx)
{
    assert(ctx.direction.IsBackwardData());

    std::vector<size_t> in_dims, in_strides;
    std::vector<size_t> weights_dims, weights_strides;
    std::vector<size_t> out_dims, out_strides;
    ComputeMlirDimsStrides(ctx.conv_problem,
                           in_dims,
                           in_strides,
                           weights_dims,
                           weights_strides,
                           out_dims,
                           out_strides);
    MlirConvArgs args =
        MakeMlirConvArgs(in_dims, in_strides, weights_dims, weights_strides, out_dims, out_strides);

    const auto& conv  = ctx.conv_problem.GetConv();
    const auto& wDesc = ctx.conv_problem.GetWeights();

    bool every_pixel_is_written = true;
    for(int i = 0; i < conv.GetSpatialDimension(); ++i)
    {
        const auto conv_stride   = conv.GetConvStrides()[i];
        const auto conv_dilation = conv.GetConvDilations()[i];
        const auto filter_size   = wDesc.GetLengths()[2 + i];

        // TODO: This can be relaxed.
        if(!(conv_dilation == 1 && conv_stride <= filter_size))
            every_pixel_is_written = false;
    }

    return [=](const std::vector<Kernel>& kernels) mutable {
        return [=](const Handle& handle, const AnyInvokeParams& primitive_parameters) mutable {
            float elapsed        = 0;
            const auto& data_ctx = primitive_parameters.CastTo<conv::DataInvokeParams>();
            const auto& tensors  = data_ctx.tensors;

            if(!every_pixel_is_written)
            {
                float zero = 0.f;
                SetTensor(handle, tensors.outDesc, tensors.out, &zero);

                if(handle.IsProfilingEnabled())
                    elapsed += handle.GetKernelTime();
            }

            SetMlirConvArgsPtr(tensors.out, tensors.in, tensors.w, args);
            for(const auto& k : kernels)
            {
                handle.Run(k)(args);
                elapsed += handle.GetKernelTime();
            }

            if(handle.IsProfilingEnabled())
            {
                handle.ResetKernelTime();
                handle.AccumKernelTime(elapsed);
            }
        };
    };
}

InvokerFactory MakeMlirWrWInvokerFactory(const ConvolutionContext& ctx)
{
    assert((ctx.direction.IsBackwardWrW()));

    std::vector<size_t> in_dims, in_strides;
    std::vector<size_t> weights_dims, weights_strides;
    std::vector<size_t> out_dims, out_strides;
    ComputeMlirDimsStrides(ctx.conv_problem,
                           in_dims,
                           in_strides,
                           weights_dims,
                           weights_strides,
                           out_dims,
                           out_strides);
    MlirConvArgs args =
        MakeMlirConvArgs(in_dims, in_strides, weights_dims, weights_strides, out_dims, out_strides);

    return [=](const std::vector<Kernel>& kernels) mutable {
        return [=](const Handle& handle, const AnyInvokeParams& primitive_parameters) mutable {
            const auto& wrw_invoke_params = primitive_parameters.CastTo<conv::WrWInvokeParams>();
            const auto& tensors           = wrw_invoke_params.tensors;

            SetMlirConvArgsPtr(tensors.x, tensors.dy, tensors.dw, args);
            handle.Run(kernels[0])(args);
        };
    };
}

} // namespace conv
} // namespace miopen
<commit_msg>[MLIR] Fixing WRW invoker by setting zero to weights (#1104)<commit_after>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2021 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/

#include <miopen/conv/invokers/mlir_impl_gemm.hpp>

#include <miopen/conv/data_invoke_params.hpp>
#include <miopen/conv/wrw_invoke_params.hpp>
#include <miopen/algorithm.hpp>
#include <miopen/handle.hpp>
#include <miopen/tensor_ops.hpp>

#include <Miir.h>

#include <boost/any.hpp>
#include <boost/range/adaptors.hpp>

namespace miopen {
namespace conv {

namespace {
struct MlirConvArgs
{
    StridedMemRef5D filter;
    StridedMemRef5D input;
    StridedMemRef5D output;
};

// Rearrange strides correctly
// In MLIR: the layout, sizes and strides are coherent. The layout information is not
// embedded into the permutation of strides.
// - For NCHW, sizes = {N, C, H, W}; strides = {C*H*W, H*W, W, 1}
// - For NHWC, sizes = {N, H, W, C}; strides = {C*H*W, W*C, C, 1}

// In MIOpen however, size and strides are not aligned. Permutation of the strides are used to
// infer actual layout
// - For NCHW, sizes = {N, C, H, W}; strides = {C*H*W, H*W, W, 1}
// - For NHWC, sizes = {N, C, H, W}; strides = {C*H*W, 1, W*C, C}
void PermuteDimsStrides(std::vector<size_t>& dims, std::vector<size_t>& strides)
{
    auto sorted_dims    = dims;
    auto sorted_strides = strides;
    auto p              = TensorDescriptor::find_permutation(dims, strides);
    std::transform(p.begin(), p.end(), sorted_dims.begin(), [&](auto i) { return dims[i]; });
    std::transform(p.begin(), p.end(), sorted_strides.begin(), [&](auto i) { return strides[i]; });
    dims    = sorted_dims;
    strides = sorted_strides;
};

void InsertGToDimsStrides(const std::string& layout,
                          char dim,
                          int group_count,
                          std::vector<size_t>& dims,
                          std::vector<size_t>& strides)
{
    std::size_t index = layout.find(dim);
    if(index == std::string::npos)
        MIOPEN_THROW("Failed to find channel in the layout");

    // For dimensions,
    //    Insert an additional dimension g before channel
    //    Amend the channel size to be channel_size / group_count
    dims[index] /= group_count;
    dims.insert(dims.begin() + index, group_count);

    // For strides,
    //   The channel stride remain the same
    //   Insert an additional group stride to be channel_stride * new_channel_size
    strides.insert(strides.begin() + index, strides[index] * dims[index + 1]);
}

void ComputeMlirDimsStrides(const conv::ProblemDescription& conv_problem,
                            std::vector<size_t>& in_dims,
                            std::vector<size_t>& in_strides,
                            std::vector<size_t>& weights_dims,
                            std::vector<size_t>& weights_strides,
                            std::vector<size_t>& out_dims,
                            std::vector<size_t>& out_strides)
{
    auto group_count = conv_problem.GetGroupCount();

    TensorDescriptor in;
    if(conv_problem.GetDirection() == conv::Direction::Forward)
        in = conv_problem.GetIn();
    else
        in = conv_problem.GetOut();

    in_dims    = in.GetLengths();
    in_strides = in.GetStrides();
    PermuteDimsStrides(in_dims, in_strides);
    // Add a virtual group dimension before input channel.
    InsertGToDimsStrides(in.GetLayout("NCHW"), 'C', group_count, in_dims, in_strides);

    // Add a virtual group dimension before output channel.
    const TensorDescriptor& weights = conv_problem.GetWeights();
    weights_dims                    = weights.GetLengths();
    weights_strides                 = weights.GetStrides();
    PermuteDimsStrides(weights_dims, weights_strides);
    InsertGToDimsStrides(
        weights.GetLayout("NCHW"), 'N', group_count, weights_dims, weights_strides);

    TensorDescriptor out;
    if(conv_problem.GetDirection() == conv::Direction::Forward)
        out = conv_problem.GetOut();
    else
        out = conv_problem.GetIn();

    out_dims    = out.GetLengths();
    out_strides = out.GetStrides();
    PermuteDimsStrides(out_dims, out_strides);
    // Add a virtual group dimension before output channel.
    InsertGToDimsStrides(out.GetLayout("NCHW"), 'C', group_count, out_dims, out_strides);
}

MlirConvArgs MakeMlirConvArgs(const std::vector<size_t>& in_dims,
                              const std::vector<size_t>& in_strides,
                              const std::vector<size_t>& weights_dims,
                              const std::vector<size_t>& weights_strides,
                              const std::vector<size_t>& out_dims,
                              const std::vector<size_t>& out_strides)
{
    auto initDimStrides = [](const std::vector<size_t>& dims,
                             const std::vector<size_t>& strides,
                             StridedMemRef5D& target) {
        std::copy(dims.cbegin(), dims.cend(), &target.sizes[0]);
        std::copy(strides.cbegin(), strides.cend(), &target.strides[0]);
    };

    StridedMemRef5D filter{nullptr, nullptr, 0, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}};
    initDimStrides(weights_dims, weights_strides, filter);
    StridedMemRef5D input{nullptr, nullptr, 0, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}};
    initDimStrides(in_dims, in_strides, input);
    StridedMemRef5D output{nullptr, nullptr, 0, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}};
    initDimStrides(out_dims, out_strides, output);

    return {filter, input, output};
}

void SetMlirConvArgsPtr(ConstData_t in, ConstData_t out, ConstData_t w, MlirConvArgs& args)
{
    void* filter = nullptr;
    void* input  = nullptr;
    void* output = nullptr;
#if MIOPEN_BACKEND_OPENCL
    clGetMemObjectInfo(w, CL_MEM_HOST_PTR, sizeof(filter), &filter, nullptr);
    clGetMemObjectInfo(in, CL_MEM_HOST_PTR, sizeof(input), &input, nullptr);
    clGetMemObjectInfo(out, CL_MEM_HOST_PTR, sizeof(output), &output, nullptr);
#elif MIOPEN_BACKEND_HIP
    // NOLINTNEXTLINE (cppcoreguidelines-pro-type-const-cast)
    filter = const_cast<void*>(w);
    // NOLINTNEXTLINE (cppcoreguidelines-pro-type-const-cast)
    input = const_cast<void*>(in);
    // NOLINTNEXTLINE (cppcoreguidelines-pro-type-const-cast)
    output = const_cast<void*>(out);
#endif

    if((filter == nullptr) || (input == nullptr) || (output == nullptr))
        MIOPEN_THROW("Invalid device pointers");

    args.filter.basePtr = filter;
    args.filter.data    = filter;
    args.input.basePtr  = input;
    args.input.data     = input;
    args.output.basePtr = output;
    args.output.data    = output;
}
} // Anonymous namespace

InvokerFactory MakeMlirFwdInvokerFactory(const ConvolutionContext& ctx)
{
    assert((ctx.direction.IsForward()));

    std::vector<size_t> in_dims, in_strides;
    std::vector<size_t> weights_dims, weights_strides;
    std::vector<size_t> out_dims, out_strides;
    ComputeMlirDimsStrides(ctx.conv_problem,
                           in_dims,
                           in_strides,
                           weights_dims,
                           weights_strides,
                           out_dims,
                           out_strides);

    MlirConvArgs args =
        MakeMlirConvArgs(in_dims, in_strides, weights_dims, weights_strides, out_dims, out_strides);

    return [=](const std::vector<Kernel>& kernels) mutable {
        return [=](const Handle& handle, const AnyInvokeParams& primitive_parameters) mutable {
            const auto& forward_invoke_params =
                primitive_parameters.CastTo<conv::DataInvokeParams>();
            const auto& tensors = forward_invoke_params.tensors;

            SetMlirConvArgsPtr(tensors.in, tensors.out, tensors.w, args);
            handle.Run(kernels[0])(args);
        };
    };
}

InvokerFactory MakeMlirBwdInvokerFactory(const ConvolutionContext& ctx)
{
    assert(ctx.direction.IsBackwardData());

    std::vector<size_t> in_dims, in_strides;
    std::vector<size_t> weights_dims, weights_strides;
    std::vector<size_t> out_dims, out_strides;
    ComputeMlirDimsStrides(ctx.conv_problem,
                           in_dims,
                           in_strides,
                           weights_dims,
                           weights_strides,
                           out_dims,
                           out_strides);
    MlirConvArgs args =
        MakeMlirConvArgs(in_dims, in_strides, weights_dims, weights_strides, out_dims, out_strides);

    const auto& conv  = ctx.conv_problem.GetConv();
    const auto& wDesc = ctx.conv_problem.GetWeights();

    bool every_pixel_is_written = true;
    for(int i = 0; i < conv.GetSpatialDimension(); ++i)
    {
        const auto conv_stride   = conv.GetConvStrides()[i];
        const auto conv_dilation = conv.GetConvDilations()[i];
        const auto filter_size   = wDesc.GetLengths()[2 + i];

        // TODO: This can be relaxed.
        if(!(conv_dilation == 1 && conv_stride <= filter_size))
            every_pixel_is_written = false;
    }

    return [=](const std::vector<Kernel>& kernels) mutable {
        return [=](const Handle& handle, const AnyInvokeParams& primitive_parameters) mutable {
            float elapsed        = 0;
            const auto& data_ctx = primitive_parameters.CastTo<conv::DataInvokeParams>();
            const auto& tensors  = data_ctx.tensors;

            if(!every_pixel_is_written)
            {
                float zero = 0.f;
                SetTensor(handle, tensors.outDesc, tensors.out, &zero);

                if(handle.IsProfilingEnabled())
                    elapsed += handle.GetKernelTime();
            }

            SetMlirConvArgsPtr(tensors.out, tensors.in, tensors.w, args);
            for(const auto& k : kernels)
            {
                handle.Run(k)(args);
                elapsed += handle.GetKernelTime();
            }

            if(handle.IsProfilingEnabled())
            {
                handle.ResetKernelTime();
                handle.AccumKernelTime(elapsed);
            }
        };
    };
}

InvokerFactory MakeMlirWrWInvokerFactory(const ConvolutionContext& ctx)
{
    assert((ctx.direction.IsBackwardWrW()));

    std::vector<size_t> in_dims, in_strides;
    std::vector<size_t> weights_dims, weights_strides;
    std::vector<size_t> out_dims, out_strides;
    ComputeMlirDimsStrides(ctx.conv_problem,
                           in_dims,
                           in_strides,
                           weights_dims,
                           weights_strides,
                           out_dims,
                           out_strides);
    MlirConvArgs args =
        MakeMlirConvArgs(in_dims, in_strides, weights_dims, weights_strides, out_dims, out_strides);

    return [=](const std::vector<Kernel>& kernels) mutable {
        return [=](const Handle& handle, const AnyInvokeParams& primitive_parameters) mutable {
            const auto& wrw_invoke_params = primitive_parameters.CastTo<conv::WrWInvokeParams>();
            const auto& tensors           = wrw_invoke_params.tensors;

            // Only fp32 use atomic_add, which accumulate the result into dw.
            // Therefore the need for setting to zero beforehand.
            if(tensors.dwDesc.GetType() == miopenFloat)
            {
                float zero = 0.f;
                SetTensor(handle, tensors.dwDesc, tensors.dw, &zero);
            }

            SetMlirConvArgsPtr(tensors.x, tensors.dy, tensors.dw, args);
            handle.Run(kernels[0])(args);
        };
    };
}

} // namespace conv
} // namespace miopen
<|endoftext|>


<commit_before>/*
 * REmbeddedPosix.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <r/RExec.hpp>

#include <core/FilePath.hpp>

#include <boost/date_time/posix_time/posix_time_duration.hpp>

// after boost stuff to prevent length (Rf_length) symbol conflict issues
#include "REmbedded.hpp"
#include <r/RInterface.hpp>
#include <r/RErrorCategory.hpp>
#include <r/RUtil.hpp>

#include <R_ext/eventloop.h>
#include <R_ext/rlocale.h>

#include <Rembedded.h>

#ifdef __APPLE__
#include <dlfcn.h>
extern "C" void R_ProcessEvents(void);
extern "C" void (*ptr_R_ProcessEvents)(void);
#define QCF_SET_PEPTR  1  /* set ProcessEvents function pointer */
#define QCF_SET_FRONT  2  /* set application mode to front */
extern "C"  typedef void (*ptr_QuartzCocoa_SetupEventLoop)(int, unsigned long);
#endif

extern int R_running_as_main_program;  // from unix/system.c

using namespace core;

namespace r {
namespace session {

void runEmbeddedR(const core::FilePath& /*rHome*/,    // ignored on posix
                  const core::FilePath& /*userHome*/, // ignored on posix
                  bool newSession,
                  SA_TYPE defaultSaveAction,
                  const Callbacks& callbacks,
                  InternalCallbacks* pInternal)
{
   // disable R signal handlers. see src/main/main.c for the default
   // implementations. in our case ignore them for the following reasons:
   //
   // INT - no concept of Ctrl-C based interruption (use flag directly)
   //
   // SEGV, ILL, & BUS: unsupported due to prompt invoking networking
   // code (unsupported from within a signal handler)
   //
   // USR1 & USR2: same as above SEGV, etc. + we use them for other purposes
   //
   // PIPE: required for prevent interrupts to send in Rhttpd (which we
   // have replaced with our own http listener)
   //
   R_SignalHandlers = 0;

   // set message callback early so we can see initialization error messages
   ptr_R_ShowMessage = callbacks.showMessage ;

   // running as main program (affects location of R_CStackStart on platforms
   // without HAVE_LIBC_STACK_END or HAVE_KERN_USRSTACK). see also discussion
   // on R_CStackStart in 8.1.5 Threading issues
   R_running_as_main_program = 1;

   // initialize R
   const char *args[]= {"RStudio", "--interactive"};
   Rf_initialize_R(sizeof(args)/sizeof(args[0]), (char**)args);

   // For newSession = false we need to do a few things:
   //
   //   1) set R_Quiet so we startup without a banner
   //
   //   2) set LoadInitFile to supress execution of .Rprofile
   //
   //   3) we also need to make sure that .First is not executed. this is
   //      taken care of via the fact that we set RestoreAction to SA_NORESTORE
   //      which means that when setup_Rmainloop there is no .First function
   //      available to it because we haven't restored the environment yet.
   //      Note that .First is executed in the case of new sessions because
   //      it is read from .Rprofile as part of setup_Rmainloop. This implies
   //      that in our version of R the .First function must be defined in
   //      .Rprofile rather than simply saved into the global environment
   //      of the default workspace
   //
   structRstart rp;
   Rstart Rp = &rp;
   R_DefParams(Rp) ;
   Rp->R_Slave = FALSE ;
   Rp->R_Quiet = newSession ? FALSE : TRUE;
   Rp->R_Interactive = TRUE ;
   Rp->SaveAction = defaultSaveAction ;
   Rp->RestoreAction = SA_NORESTORE; // handled within initialize()
   Rp->LoadInitFile = newSession ? TRUE : FALSE;
   R_SetParams(Rp) ;

   // redirect console
   R_Interactive = TRUE; // should have also been set by call to Rf_initialize_R
   R_Consolefile = NULL;
   R_Outputfile = NULL;
   ptr_R_ReadConsole = callbacks.readConsole ;
   ptr_R_WriteConsole = NULL; // must set this to NULL for Ex to be called
   ptr_R_WriteConsoleEx = callbacks.writeConsoleEx ;
   ptr_R_EditFile = callbacks.editFile ;
   ptr_R_Busy = callbacks.busy;

   // hook messages (in case Rf_initialize_R overwrites previously set hook)
   ptr_R_ShowMessage = callbacks.showMessage ;

   // hook file handling
   ptr_R_ChooseFile = callbacks.chooseFile ;
   ptr_R_ShowFiles = callbacks.showFiles ;

   // hook history
   ptr_R_loadhistory = callbacks.loadhistory;
   ptr_R_savehistory = callbacks.savehistory;
   ptr_R_addhistory = callbacks.addhistory;

   // hook suicide, but save reference to internal suicide so we can forward
   pInternal->suicide = ptr_R_Suicide;
   ptr_R_Suicide = callbacks.suicide;

   // hook clean up, but save reference to internal clean up so can forward
   pInternal->cleanUp = ptr_R_CleanUp;
   ptr_R_CleanUp = callbacks.cleanUp ;

   // NOTE: we do not hook the following callbacks because they are targeted
   // at clients that have a stdio-based console
   //    ptr_R_ResetConsole
   //    ptr_R_FlushConsole
   //    ptr_R_ClearerrConsole

   // run main loop (does not return)
   Rf_mainloop();
}

Error completeEmbeddedRInitialization()
{
   return Success();
}

namespace event_loop {

namespace {

// currently installed polled event handler
void (*s_polledEventHandler)(void) = NULL;

// previously existing polled event handler
void (*s_oldPolledEventHandler)(void) = NULL;

// function we register with R to implement polled event handler
void polledEventHandler()
{
   s_polledEventHandler();

   if (s_oldPolledEventHandler != NULL)
      s_oldPolledEventHandler();
}

#ifdef __APPLE__

void logDLError(const std::string& message, const ErrorLocation& location)
{
   std::string errmsg(message);
   char* dlError = ::dlerror();
   if (dlError)
      errmsg += ": " + std::string(dlError);
   core::log::logErrorMessage(errmsg, location);
}

// attempt to setup quartz event loop, if this fails then log and
// return false (as a result we'll have to disable the quartz R
// function so the user doesn't get in trouble)
bool setupQuartzEventLoop()
{
   // first make sure that the gdDevices pacakage is loaded
   Error error = r::exec::executeString("library(grDevices)");
   if (error)
   {
      LOG_ERROR(error);
      return false;
   }

   // get a reference to the grDevices library
   void* pGrDevices = ::dlopen("grDevices.so",
                               RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
   if (pGrDevices)
   {
      ptr_QuartzCocoa_SetupEventLoop pSetupEventLoop  =
               (ptr_QuartzCocoa_SetupEventLoop)::dlsym(
                                             pGrDevices,
                                            "QuartzCocoa_SetupEventLoop");
      if (pSetupEventLoop)
      {
         // attempt to setup event loop
         pSetupEventLoop(QCF_SET_PEPTR|QCF_SET_FRONT, 100);

         // check that we got the ptr_R_ProcessEvents initialized
         if (ptr_R_ProcessEvents != NULL)
         {
            return true;
         }
         else
         {
            LOG_ERROR_MESSAGE("ptr_R_ProcessEvents not initialized");
            return false;
         }
      }
      else
      {
         logDLError("Error looking up QuartzCocoa_SetupEventLoop",
                    ERROR_LOCATION);
         return false;
      }
   }
   else
   {
      logDLError("Error loading grDevices.so", ERROR_LOCATION);
      return false;
   }
}

// On versions prior to R 2.12 the event pump is handled by R_ProcessEvents
// rather than by the expected R_PolledEvents mechanism. On the Mac
// R_ProcessEvents includes a hook (ptr_R_ProcessEvents) but this is
// taken by the quartz module. We therefore need a way to hook it but
// still delegate to quartz so the quartz device works. do this by
// ensuring quartz is loaded then calling QuartzCocoa_SetupEventLoop
void installAppleR_2_11_Workaround(void (*newPolledEventHandler)(void))
{
   // attempt to initialize the quartz event loop (init ptr_R_ProcessEvents
   // so that we can delegate to it after we override it)
   if (!setupQuartzEventLoop())
   {
      Error error = r::exec::RFunction(".rs.disableQuartz").call();
      if (error)
         LOG_ERROR(error);
   }

   // copy handler function
   s_polledEventHandler = newPolledEventHandler;

   // preserve old handler and set new one (note that ptr_R_ProcessEvents
   // might be NULL if we didn't succeed in setting up the quartz
   // event loop above. in this case the polled event handler will
   // ignore it
   s_oldPolledEventHandler = ptr_R_ProcessEvents;
   ptr_R_ProcessEvents = polledEventHandler;
}

#endif

} // anonymous namespace

void initializePolledEventHandler(void (*newPolledEventHandler)(void))
{
   // can only call this once
   BOOST_ASSERT(!s_polledEventHandler);

   // special hack for R 2.11.1 on OSX
#ifdef __APPLE__
   if (!r::util::hasRequiredVersion("2.12"))
   {
      installAppleR_2_11_Workaround(newPolledEventHandler);
      return;
   }
#endif

   // implementation based on addTcl() in tcltk_unix.c

   // copy handler function
   s_polledEventHandler = newPolledEventHandler;

   // preserve old handler and set new one
   s_oldPolledEventHandler = R_PolledEvents;
   R_PolledEvents = polledEventHandler;

   // set R_wait_usec
   if (R_wait_usec > 10000 || R_wait_usec == 0)
      R_wait_usec = 10000;
}

bool polledEventHandlerInitialized()
{
   return s_polledEventHandler != NULL;
}

void processEvents()
{
#ifdef __APPLE__
   R_ProcessEvents();

   // pickup X11 graphics device events (if any) via X11 input handler
   fd_set* what = R_checkActivity(0,1);
   if (what != NULL)
      R_runHandlers(R_InputHandlers, what);
#else
   // check for activity on standard input handlers (but ignore stdin).
   // return immediately if there is no input currently available
   fd_set* what = R_checkActivity(0,1);

   // run handlers on the input (or run the polled event handler if there
   // is no input currently available)
   R_runHandlers(R_InputHandlers, what);
#endif
}

} // namespace event_loop
} // namespace session
} // namespace r

<commit_msg>don't specify QCF_SET_FRONT<commit_after>/*
 * REmbeddedPosix.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <r/RExec.hpp>

#include <core/FilePath.hpp>

#include <boost/date_time/posix_time/posix_time_duration.hpp>

// after boost stuff to prevent length (Rf_length) symbol conflict issues
#include "REmbedded.hpp"
#include <r/RInterface.hpp>
#include <r/RErrorCategory.hpp>
#include <r/RUtil.hpp>

#include <R_ext/eventloop.h>
#include <R_ext/rlocale.h>

#include <Rembedded.h>

#ifdef __APPLE__
#include <dlfcn.h>
extern "C" void R_ProcessEvents(void);
extern "C" void (*ptr_R_ProcessEvents)(void);
#define QCF_SET_PEPTR  1  /* set ProcessEvents function pointer */
#define QCF_SET_FRONT  2  /* set application mode to front */
extern "C"  typedef void (*ptr_QuartzCocoa_SetupEventLoop)(int, unsigned long);
#endif

extern int R_running_as_main_program;  // from unix/system.c

using namespace core;

namespace r {
namespace session {

void runEmbeddedR(const core::FilePath& /*rHome*/,    // ignored on posix
                  const core::FilePath& /*userHome*/, // ignored on posix
                  bool newSession,
                  SA_TYPE defaultSaveAction,
                  const Callbacks& callbacks,
                  InternalCallbacks* pInternal)
{
   // disable R signal handlers. see src/main/main.c for the default
   // implementations. in our case ignore them for the following reasons:
   //
   // INT - no concept of Ctrl-C based interruption (use flag directly)
   //
   // SEGV, ILL, & BUS: unsupported due to prompt invoking networking
   // code (unsupported from within a signal handler)
   //
   // USR1 & USR2: same as above SEGV, etc. + we use them for other purposes
   //
   // PIPE: required for prevent interrupts to send in Rhttpd (which we
   // have replaced with our own http listener)
   //
   R_SignalHandlers = 0;

   // set message callback early so we can see initialization error messages
   ptr_R_ShowMessage = callbacks.showMessage ;

   // running as main program (affects location of R_CStackStart on platforms
   // without HAVE_LIBC_STACK_END or HAVE_KERN_USRSTACK). see also discussion
   // on R_CStackStart in 8.1.5 Threading issues
   R_running_as_main_program = 1;

   // initialize R
   const char *args[]= {"RStudio", "--interactive"};
   Rf_initialize_R(sizeof(args)/sizeof(args[0]), (char**)args);

   // For newSession = false we need to do a few things:
   //
   //   1) set R_Quiet so we startup without a banner
   //
   //   2) set LoadInitFile to supress execution of .Rprofile
   //
   //   3) we also need to make sure that .First is not executed. this is
   //      taken care of via the fact that we set RestoreAction to SA_NORESTORE
   //      which means that when setup_Rmainloop there is no .First function
   //      available to it because we haven't restored the environment yet.
   //      Note that .First is executed in the case of new sessions because
   //      it is read from .Rprofile as part of setup_Rmainloop. This implies
   //      that in our version of R the .First function must be defined in
   //      .Rprofile rather than simply saved into the global environment
   //      of the default workspace
   //
   structRstart rp;
   Rstart Rp = &rp;
   R_DefParams(Rp) ;
   Rp->R_Slave = FALSE ;
   Rp->R_Quiet = newSession ? FALSE : TRUE;
   Rp->R_Interactive = TRUE ;
   Rp->SaveAction = defaultSaveAction ;
   Rp->RestoreAction = SA_NORESTORE; // handled within initialize()
   Rp->LoadInitFile = newSession ? TRUE : FALSE;
   R_SetParams(Rp) ;

   // redirect console
   R_Interactive = TRUE; // should have also been set by call to Rf_initialize_R
   R_Consolefile = NULL;
   R_Outputfile = NULL;
   ptr_R_ReadConsole = callbacks.readConsole ;
   ptr_R_WriteConsole = NULL; // must set this to NULL for Ex to be called
   ptr_R_WriteConsoleEx = callbacks.writeConsoleEx ;
   ptr_R_EditFile = callbacks.editFile ;
   ptr_R_Busy = callbacks.busy;

   // hook messages (in case Rf_initialize_R overwrites previously set hook)
   ptr_R_ShowMessage = callbacks.showMessage ;

   // hook file handling
   ptr_R_ChooseFile = callbacks.chooseFile ;
   ptr_R_ShowFiles = callbacks.showFiles ;

   // hook history
   ptr_R_loadhistory = callbacks.loadhistory;
   ptr_R_savehistory = callbacks.savehistory;
   ptr_R_addhistory = callbacks.addhistory;

   // hook suicide, but save reference to internal suicide so we can forward
   pInternal->suicide = ptr_R_Suicide;
   ptr_R_Suicide = callbacks.suicide;

   // hook clean up, but save reference to internal clean up so can forward
   pInternal->cleanUp = ptr_R_CleanUp;
   ptr_R_CleanUp = callbacks.cleanUp ;

   // NOTE: we do not hook the following callbacks because they are targeted
   // at clients that have a stdio-based console
   //    ptr_R_ResetConsole
   //    ptr_R_FlushConsole
   //    ptr_R_ClearerrConsole

   // run main loop (does not return)
   Rf_mainloop();
}

Error completeEmbeddedRInitialization()
{
   return Success();
}

namespace event_loop {

namespace {

// currently installed polled event handler
void (*s_polledEventHandler)(void) = NULL;

// previously existing polled event handler
void (*s_oldPolledEventHandler)(void) = NULL;

// function we register with R to implement polled event handler
void polledEventHandler()
{
   s_polledEventHandler();

   if (s_oldPolledEventHandler != NULL)
      s_oldPolledEventHandler();
}

#ifdef __APPLE__

void logDLError(const std::string& message, const ErrorLocation& location)
{
   std::string errmsg(message);
   char* dlError = ::dlerror();
   if (dlError)
      errmsg += ": " + std::string(dlError);
   core::log::logErrorMessage(errmsg, location);
}

// Note that when we passed QCF_SET_FRONT to QuartzCocoa_SetupEventLoop
// sometimes this resulted in our application having a "bouncing"
// state which we couldn't rid ourselves of.
//
// Note that in researching the way R implements QCF_SET_FRONT I discovered
// that a depricated API is called AND an explicit call to SetFront. Another
// way to go would be to call the TransformProcessType API:
//
//   http://www.cocoadev.com/index.pl?TransformProcessType
//   http://developer.apple.com/library/mac/#documentation/Carbon/Reference/Process_Manager/Reference/reference.html%23//apple_ref/c/func/TransformProcessType
//
// Note this would look something like (cmake and includes for completeness):
/*
   find_library(CARBON_LIBRARY NAMES Carbon)
   set(LINK_FLAGS ${CARBON_LIBRARY})

   #include <Carbon/Carbon.h>
   #undef TRUE
   #undef FALSE

   static const ProcessSerialNumber thePSN = { 0, kCurrentProcess };
   ::TransformProcessType(&thePSN, kProcessTransformToForegroundApplication);
*/

// attempt to setup quartz event loop, if this fails then log and
// return false (as a result we'll have to disable the quartz R
// function so the user doesn't get in trouble)
bool setupQuartzEventLoop()
{
   // first make sure that the gdDevices pacakage is loaded
   Error error = r::exec::executeString("library(grDevices)");
   if (error)
   {
      LOG_ERROR(error);
      return false;
   }

   // get a reference to the grDevices library
   void* pGrDevices = ::dlopen("grDevices.so",
                               RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD);
   if (pGrDevices)
   {
      ptr_QuartzCocoa_SetupEventLoop pSetupEventLoop  =
               (ptr_QuartzCocoa_SetupEventLoop)::dlsym(
                                             pGrDevices,
                                            "QuartzCocoa_SetupEventLoop");
      if (pSetupEventLoop)
      {
         // attempt to setup event loop
         pSetupEventLoop(QCF_SET_PEPTR, 100);

         // check that we got the ptr_R_ProcessEvents initialized
         if (ptr_R_ProcessEvents != NULL)
         {
            return true;
         }
         else
         {
            LOG_ERROR_MESSAGE("ptr_R_ProcessEvents not initialized");
            return false;
         }
      }
      else
      {
         logDLError("Error looking up QuartzCocoa_SetupEventLoop",
                    ERROR_LOCATION);
         return false;
      }
   }
   else
   {
      logDLError("Error loading grDevices.so", ERROR_LOCATION);
      return false;
   }
}

// On versions prior to R 2.12 the event pump is handled by R_ProcessEvents
// rather than by the expected R_PolledEvents mechanism. On the Mac
// R_ProcessEvents includes a hook (ptr_R_ProcessEvents) but this is
// taken by the quartz module. We therefore need a way to hook it but
// still delegate to quartz so the quartz device works. do this by
// ensuring quartz is loaded then calling QuartzCocoa_SetupEventLoop
void installAppleR_2_11_Workaround(void (*newPolledEventHandler)(void))
{
   // attempt to initialize the quartz event loop (init ptr_R_ProcessEvents
   // so that we can delegate to it after we override it)
   if (!setupQuartzEventLoop())
   {
      Error error = r::exec::RFunction(".rs.disableQuartz").call();
      if (error)
         LOG_ERROR(error);
   }

   // copy handler function
   s_polledEventHandler = newPolledEventHandler;

   // preserve old handler and set new one (note that ptr_R_ProcessEvents
   // might be NULL if we didn't succeed in setting up the quartz
   // event loop above. in this case the polled event handler will
   // ignore it
   s_oldPolledEventHandler = ptr_R_ProcessEvents;
   ptr_R_ProcessEvents = polledEventHandler;
}

#endif

} // anonymous namespace

void initializePolledEventHandler(void (*newPolledEventHandler)(void))
{
   // can only call this once
   BOOST_ASSERT(!s_polledEventHandler);

   // special hack for R 2.11.1 on OSX
#ifdef __APPLE__
   if (!r::util::hasRequiredVersion("2.12"))
   {
      installAppleR_2_11_Workaround(newPolledEventHandler);
      return;
   }
#endif

   // implementation based on addTcl() in tcltk_unix.c

   // copy handler function
   s_polledEventHandler = newPolledEventHandler;

   // preserve old handler and set new one
   s_oldPolledEventHandler = R_PolledEvents;
   R_PolledEvents = polledEventHandler;

   // set R_wait_usec
   if (R_wait_usec > 10000 || R_wait_usec == 0)
      R_wait_usec = 10000;
}

bool polledEventHandlerInitialized()
{
   return s_polledEventHandler != NULL;
}

void processEvents()
{
#ifdef __APPLE__
   R_ProcessEvents();

   // pickup X11 graphics device events (if any) via X11 input handler
   fd_set* what = R_checkActivity(0,1);
   if (what != NULL)
      R_runHandlers(R_InputHandlers, what);
#else
   // check for activity on standard input handlers (but ignore stdin).
   // return immediately if there is no input currently available
   fd_set* what = R_checkActivity(0,1);

   // run handlers on the input (or run the polled event handler if there
   // is no input currently available)
   R_runHandlers(R_InputHandlers, what);
#endif
}

} // namespace event_loop
} // namespace session
} // namespace r

<|endoftext|>


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

#include "curlpp/internal/global.h"
#include "curlpp/internal/CurlHandle.hpp"
#include "curlpp/internal/OptionSetter.hpp"

#include "utilspp/Functors.hpp"

#include <string>
#include <iostream>

namespace curlpp
{

namespace internal
{

struct Callbacks
{
	static size_t
	WriteCallback(char * buffer, size_t size, size_t nitems, internal::CurlHandle * handle)
	{
		return handle->executeWriteFunctor(buffer, size, nitems);
	};

	static size_t
	StreamWriteCallback(char * buffer, size_t size, size_t nitems, std::ostream * stream)
	{
		size_t realwrote = size * nitems;
		stream->write(buffer, static_cast<std::streamsize>(realwrote));
		if(!(*stream))
			realwrote = 0;

		return realwrote;
	};

	static size_t
	HeaderCallback(char * buffer, size_t size, size_t nitems, internal::CurlHandle * handle)
	{
		return handle->executeHeaderFunctor(buffer, size, nitems);
	};

	static size_t
	ReadCallback(char * buffer, size_t size, size_t nitems, internal::CurlHandle * handle)
	{
		return handle->executeReadFunctor(buffer, size, nitems);
	};

	static size_t
	StreamReadCallback(char * buffer, size_t size, size_t nitems, std::istream * stream)
	{
		size_t realread = stream->readsome(buffer, static_cast<std::streamsize>(size * nitems));
		if(!(*stream))
			realread = CURL_READFUNC_ABORT;

		return realread;
	};

	static int
	ProgressCallback(internal::CurlHandle * handle,
											double dltotal,
											double dlnow,
											double ultotal,
											double ulnow)
	{
		return handle->executeProgressFunctor(dltotal, dlnow, ultotal, ulnow);
	};

	static int
	DebugCallback(CURL *,
									curl_infotype type,
									char * data,
									size_t size,
									internal::CurlHandle * handle)
	{
		return handle->executeDebugFunctor(type, data, size);
	};

	static CURLcode
	SslCtxCallback(CURL *,
										void * ssl_ctx,
										internal::CurlHandle * handle)
	{
		return handle->executeSslCtxFunctor(ssl_ctx);
	};

};

void OptionSetter<curlpp::Forms, CURLOPT_HTTPPOST>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_HTTPPOST, value.cHttpPost());
};

void OptionSetter<curlpp::types::WriteFunctionFunctor, CURLOPT_WRITEFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_WRITEFUNCTION, Callbacks::WriteCallback);
	handle->option(CURLOPT_WRITEDATA, handle);
	handle->setWriteFunctor(value);
};

#ifdef HAVE_BOOST

void OptionSetter<curlpp::types::BoostWriteFunction, CURLOPT_WRITEFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_WRITEFUNCTION, Callbacks::WriteCallback);
	handle->option(CURLOPT_WRITEDATA, handle);
	handle->setWriteFunctor(curlpp::types::WriteFunctionFunctor(&value,
		&curlpp::types::BoostWriteFunction::operator()));
};

#endif

void OptionSetter<FILE *, CURLOPT_WRITEDATA>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_WRITEFUNCTION, (void *)NULL);
	handle->option(CURLOPT_WRITEDATA, value);
};

void OptionSetter<std::ostream *, CURLOPT_WRITEDATA>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_WRITEFUNCTION, (void *)Callbacks::StreamWriteCallback);
	handle->option(CURLOPT_WRITEDATA, value);
};

void OptionSetter<curlpp::types::ReadFunctionFunctor, CURLOPT_READFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_READFUNCTION, Callbacks::ReadCallback);
	handle->option(CURLOPT_READDATA, handle);
	handle->setReadFunctor(value);
};

#ifdef HAVE_BOOST

void OptionSetter<curlpp::types::BoostReadFunction, CURLOPT_READFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_READFUNCTION, Callbacks::ReadCallback);
	handle->option(CURLOPT_READDATA, handle);
	handle->setReadFunctor(value);
};

#endif

void OptionSetter<FILE *, CURLOPT_READDATA>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_READFUNCTION, (void *)NULL);
	handle->option(CURLOPT_READDATA, value);
};

void OptionSetter<std::istream *, CURLOPT_READDATA>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_READFUNCTION, (void *)Callbacks::StreamReadCallback);
	handle->option(CURLOPT_READDATA, value);
};

void OptionSetter<curlpp::types::ProgressFunctionFunctor, CURLOPT_PROGRESSFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_PROGRESSFUNCTION, Callbacks::ProgressCallback);
	handle->option(CURLOPT_PROGRESSDATA, handle);
	handle->setProgressFunctor(value);
};

#ifdef HAVE_BOOST

void OptionSetter<curlpp::types::BoostProgressFunction, CURLOPT_PROGRESSFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_PROGRESSFUNCTION, Callbacks::ProgressCallback);
	handle->option(CURLOPT_PROGRESSDATA, handle);
	handle->setProgressFunctor(value);
};

#endif

void OptionSetter<curlpp::types::WriteFunctionFunctor, CURLOPT_HEADERFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_HEADERFUNCTION, Callbacks::HeaderCallback);
	handle->option(CURLOPT_HEADERDATA, handle);
	handle->setHeaderFunctor(value);
};

#ifdef HAVE_BOOST

void OptionSetter<curlpp::types::BoostWriteFunction, CURLOPT_HEADERFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_HEADERFUNCTION, Callbacks::HeaderCallback);
	handle->option(CURLOPT_HEADERDATA, handle);
	handle->setHeaderFunctor(value);
};

#endif

void OptionSetter<curlpp::types::DebugFunctionFunctor, CURLOPT_DEBUGFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_DEBUGFUNCTION, Callbacks::DebugCallback);
	handle->option(CURLOPT_DEBUGDATA, handle);
	handle->setDebugFunctor(value);
};

#ifdef HAVE_BOOST

void OptionSetter<curlpp::types::BoostDebugFunction, CURLOPT_DEBUGFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_DEBUGFUNCTION, Callbacks::DebugCallback);
	handle->option(CURLOPT_DEBUGDATA, handle);
	handle->setDebugFunctor(value);
};

#endif

void OptionSetter<curlpp::types::SslCtxFunctionFunctor, CURLOPT_SSL_CTX_FUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_SSL_CTX_FUNCTION, Callbacks::SslCtxCallback);
	handle->option(CURLOPT_SSL_CTX_DATA, handle);
	handle->setSslCtxFunctor(value);
};

#ifdef HAVE_BOOST

void OptionSetter<curlpp::types::BoostSslCtxFunction, CURLOPT_SSL_CTX_FUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_SSL_CTX_FUNCTION, Callbacks::SslCtxCallback);
	handle->option(CURLOPT_SSL_CTX_DATA, handle);
	handle->setSslCtxFunctor(value);
};

#endif

}// namespace internal

}// namespace curlpp

<commit_msg>Supressing warning in curlpp<commit_after>/*
*    Copyright (c) <2002-2009> <Jean-Philippe Barrette-LaPierre>
*
*    Permission is hereby granted, free of charge, to any person obtaining
*    a copy of this software and associated documentation files
*    (curlpp), to deal in the Software without restriction,
*    including without limitation the rights to use, copy, modify, merge,
*    publish, distribute, sublicense, and/or sell copies of the Software,
*    and to permit persons to whom the Software is furnished to do so,
*    subject to the following conditions:
*
*    The above copyright notice and this permission notice shall be included
*    in all copies or substantial portions of the Software.
*
*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
*    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
*    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
*    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
*    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#include "curlpp/internal/global.h"
#include "curlpp/internal/CurlHandle.hpp"
#include "curlpp/internal/OptionSetter.hpp"

#include "utilspp/Functors.hpp"

#include <string>
#include <iostream>

namespace curlpp
{

namespace internal
{

struct Callbacks
{
	static size_t
	WriteCallback(char * buffer, size_t size, size_t nitems, internal::CurlHandle * handle)
	{
		return handle->executeWriteFunctor(buffer, size, nitems);
	};

	static size_t
	StreamWriteCallback(char * buffer, size_t size, size_t nitems, std::ostream * stream)
	{
		size_t realwrote = size * nitems;
		stream->write(buffer, static_cast<std::streamsize>(realwrote));
		if(!(*stream))
			realwrote = 0;

		return realwrote;
	};

	static size_t
	HeaderCallback(char * buffer, size_t size, size_t nitems, internal::CurlHandle * handle)
	{
		return handle->executeHeaderFunctor(buffer, size, nitems);
	};

	static size_t
	ReadCallback(char * buffer, size_t size, size_t nitems, internal::CurlHandle * handle)
	{
		return handle->executeReadFunctor(buffer, size, nitems);
	};

#pragma warning(push)
#pragma warning(disable: 4996) // ->readsome is unsafe function

	static size_t
	StreamReadCallback(char * buffer, size_t size, size_t nitems, std::istream * stream)
	{
		size_t realread = stream->readsome(buffer, static_cast<std::streamsize>(size * nitems));
		if(!(*stream))
			realread = CURL_READFUNC_ABORT;

		return realread;
	};

#pragma warning(pop)

	static int
	ProgressCallback(internal::CurlHandle * handle,
											double dltotal,
											double dlnow,
											double ultotal,
											double ulnow)
	{
		return handle->executeProgressFunctor(dltotal, dlnow, ultotal, ulnow);
	};

	static int
	DebugCallback(CURL *,
									curl_infotype type,
									char * data,
									size_t size,
									internal::CurlHandle * handle)
	{
		return handle->executeDebugFunctor(type, data, size);
	};

	static CURLcode
	SslCtxCallback(CURL *,
										void * ssl_ctx,
										internal::CurlHandle * handle)
	{
		return handle->executeSslCtxFunctor(ssl_ctx);
	};

};

void OptionSetter<curlpp::Forms, CURLOPT_HTTPPOST>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_HTTPPOST, value.cHttpPost());
};

void OptionSetter<curlpp::types::WriteFunctionFunctor, CURLOPT_WRITEFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_WRITEFUNCTION, Callbacks::WriteCallback);
	handle->option(CURLOPT_WRITEDATA, handle);
	handle->setWriteFunctor(value);
};

#ifdef HAVE_BOOST

void OptionSetter<curlpp::types::BoostWriteFunction, CURLOPT_WRITEFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_WRITEFUNCTION, Callbacks::WriteCallback);
	handle->option(CURLOPT_WRITEDATA, handle);
	handle->setWriteFunctor(curlpp::types::WriteFunctionFunctor(&value,
		&curlpp::types::BoostWriteFunction::operator()));
};

#endif

void OptionSetter<FILE *, CURLOPT_WRITEDATA>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_WRITEFUNCTION, (void *)NULL);
	handle->option(CURLOPT_WRITEDATA, value);
};

void OptionSetter<std::ostream *, CURLOPT_WRITEDATA>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_WRITEFUNCTION, (void *)Callbacks::StreamWriteCallback);
	handle->option(CURLOPT_WRITEDATA, value);
};

void OptionSetter<curlpp::types::ReadFunctionFunctor, CURLOPT_READFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_READFUNCTION, Callbacks::ReadCallback);
	handle->option(CURLOPT_READDATA, handle);
	handle->setReadFunctor(value);
};

#ifdef HAVE_BOOST

void OptionSetter<curlpp::types::BoostReadFunction, CURLOPT_READFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_READFUNCTION, Callbacks::ReadCallback);
	handle->option(CURLOPT_READDATA, handle);
	handle->setReadFunctor(value);
};

#endif

void OptionSetter<FILE *, CURLOPT_READDATA>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_READFUNCTION, (void *)NULL);
	handle->option(CURLOPT_READDATA, value);
};

void OptionSetter<std::istream *, CURLOPT_READDATA>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_READFUNCTION, (void *)Callbacks::StreamReadCallback);
	handle->option(CURLOPT_READDATA, value);
};

void OptionSetter<curlpp::types::ProgressFunctionFunctor, CURLOPT_PROGRESSFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_PROGRESSFUNCTION, Callbacks::ProgressCallback);
	handle->option(CURLOPT_PROGRESSDATA, handle);
	handle->setProgressFunctor(value);
};

#ifdef HAVE_BOOST

void OptionSetter<curlpp::types::BoostProgressFunction, CURLOPT_PROGRESSFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_PROGRESSFUNCTION, Callbacks::ProgressCallback);
	handle->option(CURLOPT_PROGRESSDATA, handle);
	handle->setProgressFunctor(value);
};

#endif

void OptionSetter<curlpp::types::WriteFunctionFunctor, CURLOPT_HEADERFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_HEADERFUNCTION, Callbacks::HeaderCallback);
	handle->option(CURLOPT_HEADERDATA, handle);
	handle->setHeaderFunctor(value);
};

#ifdef HAVE_BOOST

void OptionSetter<curlpp::types::BoostWriteFunction, CURLOPT_HEADERFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_HEADERFUNCTION, Callbacks::HeaderCallback);
	handle->option(CURLOPT_HEADERDATA, handle);
	handle->setHeaderFunctor(value);
};

#endif

void OptionSetter<curlpp::types::DebugFunctionFunctor, CURLOPT_DEBUGFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_DEBUGFUNCTION, Callbacks::DebugCallback);
	handle->option(CURLOPT_DEBUGDATA, handle);
	handle->setDebugFunctor(value);
};

#ifdef HAVE_BOOST

void OptionSetter<curlpp::types::BoostDebugFunction, CURLOPT_DEBUGFUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_DEBUGFUNCTION, Callbacks::DebugCallback);
	handle->option(CURLOPT_DEBUGDATA, handle);
	handle->setDebugFunctor(value);
};

#endif

void OptionSetter<curlpp::types::SslCtxFunctionFunctor, CURLOPT_SSL_CTX_FUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_SSL_CTX_FUNCTION, Callbacks::SslCtxCallback);
	handle->option(CURLOPT_SSL_CTX_DATA, handle);
	handle->setSslCtxFunctor(value);
};

#ifdef HAVE_BOOST

void OptionSetter<curlpp::types::BoostSslCtxFunction, CURLOPT_SSL_CTX_FUNCTION>
::setOpt(internal::CurlHandle * handle, ParamType value)
{
	handle->option(CURLOPT_SSL_CTX_FUNCTION, Callbacks::SslCtxCallback);
	handle->option(CURLOPT_SSL_CTX_DATA, handle);
	handle->setSslCtxFunctor(value);
};

#endif

}// namespace internal

}// namespace curlpp

<|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2021.  All rights reserved
 */
#include "../StroikaPreComp.h"

#include "../../Foundation/Execution/Sleep.h"

#include "Capturer.h"

using namespace Stroika::Foundation;
using namespace Stroika::Foundation::Containers;
using namespace Stroika::Foundation::Memory;

using namespace Stroika::Frameworks;
using namespace Stroika::Frameworks::SystemPerformance;

/*
 ********************************************************************************
 ************************* SystemPerformance::Capturer **************************
 ********************************************************************************
 */
Capturer::Capturer (const CaptureSet& cs)
{
    fCaptureSets_.rwget ()->Add (cs);
    RunnerOnce_ ();
    ManageRunner_ (true);
}

Collection<Capturer::NewMeasurementsCallbackType> Capturer::GetMeasurementsCallbacks () const
{
    return fCallbacks_;
}

void Capturer::SetMeasurementsCallbacks (const Collection<NewMeasurementsCallbackType>& callbacks)
{
    fCallbacks_ = callbacks;
}

void Capturer::AddMeasurementsCallback (const NewMeasurementsCallbackType& cb)
{
    fCallbacks_.rwget ()->Add (cb);
}

void Capturer::RemoveMeasurementsCallback (const NewMeasurementsCallbackType& cb)
{
    fCallbacks_.rwget ()->Remove (cb);
}

Collection<CaptureSet> Capturer::GetCaptureSets () const
{
    return fCaptureSets_;
}

void Capturer::SetCaptureSets (const Collection<CaptureSet>& captureSets)
{
    fCaptureSets_ = captureSets;
    ManageRunner_ (not fCaptureSets_.cget ()->empty ());
    Assert (fCaptureSets_.cget ()->size () <= 1); // only case we support so far
}

void Capturer::AddCaptureSet (const CaptureSet& cs)
{
    fCaptureSets_.rwget ()->Add (cs);
    ManageRunner_ (true);
    Assert (fCaptureSets_.cget ()->size () == 1); // only case we support so far
}

void Capturer::ManageRunner_ (bool on)
{
    bool threadPoolRunning = fThreadPool_.GetTasksCount () != 0;
    if (on) {
        if (not threadPoolRunning) {
            fThreadPool_.AddTask ([this] () { Runner_ (); });
            fThreadPool_.SetPoolSize (1);
        }
    }
    else {
        if (threadPoolRunning) {
            fThreadPool_.AbortTasks ();
            fThreadPool_.SetPoolSize (0);
        }
    }
}

void Capturer::Runner_ ()
{
    while (true) {
        // wrong - period should be from leading edge of last run!!! - and we should probably have ... - probably one task in each threadpool...
        Duration d = fCaptureSets_.load ().Select<Duration> ([] (auto i) { return i.GetRunPeriod (); }).MinValue (30s);
        Execution::Sleep (d);
        RunnerOnce_ ();
    }
}

void Capturer::RunnerOnce_ ()
{
    // SUPER MEGA OVERSIMPLIFED.
    // @todo - fix to submit each subtask as its own runnable so it can leverage threadpool
    // @todo real job waiting for jsut right time before starting next run through capturesets
    // @todo support more than one capture set.

    MeasurementSet measurements;
    for (CaptureSet cs : fCaptureSets_.load ()) {
        // @todo fix!!!

        for (Instrument i : cs.GetInstrumentSet ()) {
            try {
                auto m = i.Capture ();
                measurements.fMeasurements += m.fMeasurements;
                measurements.fMeasuredAt = m.fMeasuredAt;       // weak way to merge but hopefully good enuf for now...
            }
            catch (const Execution::Thread::AbortException&) {
                Execution::ReThrow ();
            }
            catch (...) {
                DbgTrace ("Eating exception in Capturer runner");
            }
        }
    }
    UpdateMeasurementSet_ (measurements);
}

void Capturer::UpdateMeasurementSet_ (const MeasurementSet& ms)
{
    fCurrentMeasurementSet_ = ms;
    for (const auto& cb : fCallbacks_.load ()) {
        cb (ms);
    }
}
<commit_msg>cosmetic<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2021.  All rights reserved
 */
#include "../StroikaPreComp.h"

#include "../../Foundation/Execution/Sleep.h"

#include "Capturer.h"

using namespace Stroika::Foundation;
using namespace Stroika::Foundation::Containers;
using namespace Stroika::Foundation::Memory;

using namespace Stroika::Frameworks;
using namespace Stroika::Frameworks::SystemPerformance;

/*
 ********************************************************************************
 ************************* SystemPerformance::Capturer **************************
 ********************************************************************************
 */
Capturer::Capturer (const CaptureSet& cs)
{
    fCaptureSets_.rwget ()->Add (cs);
    RunnerOnce_ ();
    ManageRunner_ (true);
}

Collection<Capturer::NewMeasurementsCallbackType> Capturer::GetMeasurementsCallbacks () const
{
    return fCallbacks_;
}

void Capturer::SetMeasurementsCallbacks (const Collection<NewMeasurementsCallbackType>& callbacks)
{
    fCallbacks_ = callbacks;
}

void Capturer::AddMeasurementsCallback (const NewMeasurementsCallbackType& cb)
{
    fCallbacks_.rwget ()->Add (cb);
}

void Capturer::RemoveMeasurementsCallback (const NewMeasurementsCallbackType& cb)
{
    fCallbacks_.rwget ()->Remove (cb);
}

Collection<CaptureSet> Capturer::GetCaptureSets () const
{
    return fCaptureSets_;
}

void Capturer::SetCaptureSets (const Collection<CaptureSet>& captureSets)
{
    fCaptureSets_ = captureSets;
    ManageRunner_ (not fCaptureSets_.cget ()->empty ());
    Assert (fCaptureSets_.cget ()->size () <= 1); // only case we support so far
}

void Capturer::AddCaptureSet (const CaptureSet& cs)
{
    fCaptureSets_.rwget ()->Add (cs);
    ManageRunner_ (true);
    Assert (fCaptureSets_.cget ()->size () == 1); // only case we support so far
}

void Capturer::ManageRunner_ (bool on)
{
    bool threadPoolRunning = fThreadPool_.GetTasksCount () != 0;
    if (on) {
        if (not threadPoolRunning) {
            fThreadPool_.AddTask ([this] () { Runner_ (); });
            fThreadPool_.SetPoolSize (1);
        }
    }
    else {
        if (threadPoolRunning) {
            fThreadPool_.AbortTasks ();
            fThreadPool_.SetPoolSize (0);
        }
    }
}

void Capturer::Runner_ ()
{
    while (true) {
        // wrong - period should be from leading edge of last run!!! - and we should probably have ... - probably one task in each threadpool...
        Duration d = fCaptureSets_.load ().Select<Duration> ([] (auto i) { return i.GetRunPeriod (); }).MinValue (30s);
        Execution::Sleep (d);
        RunnerOnce_ ();
    }
}

void Capturer::RunnerOnce_ ()
{
    // SUPER MEGA OVERSIMPLIFED.
    // @todo - fix to submit each subtask as its own runnable so it can leverage threadpool
    // @todo real job waiting for jsut right time before starting next run through capturesets
    // @todo support more than one capture set.

    MeasurementSet measurements;
    for (CaptureSet cs : fCaptureSets_.load ()) {
        // @todo fix!!!

        for (Instrument i : cs.GetInstrumentSet ()) {
            try {
                auto m = i.Capture ();
                measurements.fMeasurements += m.fMeasurements;
                measurements.fMeasuredAt = m.fMeasuredAt; // weak way to merge but hopefully good enuf for now...
            }
            catch (const Execution::Thread::AbortException&) {
                Execution::ReThrow ();
            }
            catch (...) {
                DbgTrace ("Eating exception in Capturer runner");
            }
        }
    }
    UpdateMeasurementSet_ (measurements);
}

void Capturer::UpdateMeasurementSet_ (const MeasurementSet& ms)
{
    fCurrentMeasurementSet_ = ms;
    for (const auto& cb : fCallbacks_.load ()) {
        cb (ms);
    }
}
<|endoftext|>