<commit_before>#include "MP3DataProvider.h"
#include "Utils.h"
#include "id3v2lib.h"

extern "C"
{
#include "minimp3/minimp3.h"
}

clMP3DataProvider::clMP3DataProvider( const std::shared_ptr<clBlob>& Data )
: m_Data( Data )
, m_Format()
, m_DecodingBuffer( MP3_MAX_SAMPLES_PER_FRAME * 16 )
, m_BufferUsed( 0 )
, m_StreamPos( 0 )
, m_InitialStreamPos( 0 )
, m_IsEndOfStream( false )
, m_MP3Decoder( mp3_create() )
{
	LoadMP3Info();

	m_Format.m_NumChannels      = m_MP3Info.channels;
	m_Format.m_SamplesPerSecond = m_MP3Info.sample_rate;
	m_Format.m_BitsPerSample    = 16;
}

clMP3DataProvider::~clMP3DataProvider()
{
	mp3_done( (mp3_decoder_t*)m_MP3Decoder );
}

void clMP3DataProvider::SkipTags()
{
	ID3v2_header* ID3TagHeader = get_tag_header_with_buffer(
		reinterpret_cast<const char*>( m_Data->GetDataPtr() + m_StreamPos ),
		static_cast<int>( m_Data->GetDataSize() - m_StreamPos )
	);

	if ( ID3TagHeader )
	{
		m_StreamPos += ID3TagHeader->tag_size;
		free( ID3TagHeader );
	}
}

void clMP3DataProvider::LoadMP3Info()
{
	SkipTags();

	int byteCount = mp3_decode(
		(mp3_decoder_t*)m_MP3Decoder,
		m_Data ? const_cast<uint8_t*>( m_Data->GetDataPtr() + m_StreamPos ) : nullptr,
		m_Data ? m_Data->GetDataSize() - m_StreamPos: 0,
		(signed short*)m_DecodingBuffer.data(),
		&m_MP3Info
	);

	m_StreamPos += byteCount;
	m_InitialStreamPos = m_StreamPos;
}

const uint8_t* clMP3DataProvider::GetWaveData() const
{
	return m_DecodingBuffer.data();
}

size_t clMP3DataProvider::GetWaveDataSize() const
{
	return m_BufferUsed;
}

int clMP3DataProvider::DecodeFromFile( size_t BytesRead )
{
	if ( m_IsEndOfStream || !m_Data )
	{
		return 0;
	}

	size_t ByteCount = mp3_decode(
		(mp3_decoder_t*)m_MP3Decoder,
		const_cast<uint8_t*>( m_Data->GetDataPtr() + m_StreamPos ),
		m_Data->GetDataSize() - m_StreamPos,
		(signed short*)( m_DecodingBuffer.data() + BytesRead ),
		&m_MP3Info
	);

	m_Format.m_NumChannels      = m_MP3Info.channels;
	m_Format.m_SamplesPerSecond = m_MP3Info.sample_rate;

	m_StreamPos += ByteCount;

	if ( m_StreamPos >= m_Data->GetDataSize() || !ByteCount )
	{
		m_IsEndOfStream = true;
	}

	return m_MP3Info.audio_bytes;
}

size_t clMP3DataProvider::StreamWaveData( size_t Size )
{
	if ( m_IsEndOfStream )
	{
		return 0;
	}

	size_t OldSize = m_DecodingBuffer.size();

	if ( Size > OldSize )
	{
		m_DecodingBuffer.resize( Size, 0 );
	}

	size_t BytesRead = 0;

	while ( BytesRead + MP3_MAX_SAMPLES_PER_FRAME * 2 < Size )
	{
		int Ret = DecodeFromFile( BytesRead );

		if ( Ret > 0 )
		{
			BytesRead += Ret;
		}
		else if ( Ret == 0 )
		{
			m_IsEndOfStream = true;
			break;
		}
		else
		{
			// there is no audio data in this frame, just skip it
		}
	}

	m_BufferUsed = BytesRead;

	return m_BufferUsed;
}

void clMP3DataProvider::Seek( float Seconds )
{
	mp3_done( (mp3_decoder_t*)m_MP3Decoder );
	m_MP3Decoder = mp3_create();

	m_StreamPos = 0;
	m_IsEndOfStream = false;

	LoadMP3Info();
}
<commit_msg>OS X: compilation fix<commit_after>#include "MP3DataProvider.h"
#include "Utils.h"
#include "id3v2lib.h"

extern "C"
{
#include "minimp3/minimp3.h"
}

clMP3DataProvider::clMP3DataProvider( const std::shared_ptr<clBlob>& Data )
: m_Data( Data )
, m_Format()
, m_DecodingBuffer( MP3_MAX_SAMPLES_PER_FRAME * 16 )
, m_BufferUsed( 0 )
, m_StreamPos( 0 )
, m_InitialStreamPos( 0 )
, m_IsEndOfStream( false )
, m_MP3Decoder( mp3_create() )
{
	LoadMP3Info();

	m_Format.m_NumChannels      = m_MP3Info.channels;
	m_Format.m_SamplesPerSecond = m_MP3Info.sample_rate;
	m_Format.m_BitsPerSample    = 16;
}

clMP3DataProvider::~clMP3DataProvider()
{
	mp3_done( (mp3_decoder_t*)m_MP3Decoder );
}

void clMP3DataProvider::SkipTags()
{
	ID3v2_header* ID3TagHeader = get_tag_header_with_buffer(
		reinterpret_cast<const char*>( m_Data->GetDataPtr() + m_StreamPos ),
		static_cast<int>( m_Data->GetDataSize() - m_StreamPos )
	);

	if ( ID3TagHeader )
	{
		m_StreamPos += ID3TagHeader->tag_size;
		delete_header( ID3TagHeader );
	}
}

void clMP3DataProvider::LoadMP3Info()
{
	SkipTags();

	int byteCount = mp3_decode(
		(mp3_decoder_t*)m_MP3Decoder,
		m_Data ? const_cast<uint8_t*>( m_Data->GetDataPtr() + m_StreamPos ) : nullptr,
		m_Data ? m_Data->GetDataSize() - m_StreamPos: 0,
		(signed short*)m_DecodingBuffer.data(),
		&m_MP3Info
	);

	m_StreamPos += byteCount;
	m_InitialStreamPos = m_StreamPos;
}

const uint8_t* clMP3DataProvider::GetWaveData() const
{
	return m_DecodingBuffer.data();
}

size_t clMP3DataProvider::GetWaveDataSize() const
{
	return m_BufferUsed;
}

int clMP3DataProvider::DecodeFromFile( size_t BytesRead )
{
	if ( m_IsEndOfStream || !m_Data )
	{
		return 0;
	}

	size_t ByteCount = mp3_decode(
		(mp3_decoder_t*)m_MP3Decoder,
		const_cast<uint8_t*>( m_Data->GetDataPtr() + m_StreamPos ),
		m_Data->GetDataSize() - m_StreamPos,
		(signed short*)( m_DecodingBuffer.data() + BytesRead ),
		&m_MP3Info
	);

	m_Format.m_NumChannels      = m_MP3Info.channels;
	m_Format.m_SamplesPerSecond = m_MP3Info.sample_rate;

	m_StreamPos += ByteCount;

	if ( m_StreamPos >= m_Data->GetDataSize() || !ByteCount )
	{
		m_IsEndOfStream = true;
	}

	return m_MP3Info.audio_bytes;
}

size_t clMP3DataProvider::StreamWaveData( size_t Size )
{
	if ( m_IsEndOfStream )
	{
		return 0;
	}

	size_t OldSize = m_DecodingBuffer.size();

	if ( Size > OldSize )
	{
		m_DecodingBuffer.resize( Size, 0 );
	}

	size_t BytesRead = 0;

	while ( BytesRead + MP3_MAX_SAMPLES_PER_FRAME * 2 < Size )
	{
		int Ret = DecodeFromFile( BytesRead );

		if ( Ret > 0 )
		{
			BytesRead += Ret;
		}
		else if ( Ret == 0 )
		{
			m_IsEndOfStream = true;
			break;
		}
		else
		{
			// there is no audio data in this frame, just skip it
		}
	}

	m_BufferUsed = BytesRead;

	return m_BufferUsed;
}

void clMP3DataProvider::Seek( float Seconds )
{
	mp3_done( (mp3_decoder_t*)m_MP3Decoder );
	m_MP3Decoder = mp3_create();

	m_StreamPos = 0;
	m_IsEndOfStream = false;

	LoadMP3Info();
}
<|endoftext|>


<commit_before>/**
 * @file
 */
#pragma once

#include "bi/common/TypeParameterised.hpp"
#include "bi/io/indentable_ostream.hpp"

namespace bi {
/**
 * C++ code generator.
 *
 * @ingroup io
 */
class CppBaseGenerator: public indentable_ostream {
public:
  CppBaseGenerator(std::ostream& base, const int level = 0,
      const bool header = false);

  using indentable_ostream::visit;

  virtual void visit(const Name* o);

  virtual void visit(const ExpressionList* o);
  virtual void visit(const Literal<bool>* o);
  virtual void visit(const Literal<int64_t>* o);
  virtual void visit(const Literal<double>* o);
  virtual void visit(const Literal<const char*>* o);
  virtual void visit(const Parentheses* o);
  virtual void visit(const Sequence* o);
  virtual void visit(const Cast* o);
  virtual void visit(const Call<Unknown>* o);
  virtual void visit(const Call<Function>* o);
  virtual void visit(const Call<MemberFunction>* o);
  virtual void visit(const Call<Fiber>* o);
  virtual void visit(const Call<MemberFiber>* o);
  virtual void visit(const Call<Parameter>* o);
  virtual void visit(const Call<LocalVariable>* o);
  virtual void visit(const Call<MemberVariable>* o);
  virtual void visit(const Call<GlobalVariable>* o);
  virtual void visit(const Call<BinaryOperator>* o);
  virtual void visit(const Call<UnaryOperator>* o);
  virtual void visit(const Assign* o);
  virtual void visit(const Slice* o);
  virtual void visit(const Query* o);
  virtual void visit(const Get* o);
  virtual void visit(const LambdaFunction* o);
  virtual void visit(const Span* o);
  virtual void visit(const Index* o);
  virtual void visit(const Range* o);
  virtual void visit(const Member* o);
  virtual void visit(const Global* o);
  virtual void visit(const This* o);
  virtual void visit(const Super* o);
  virtual void visit(const Nil* o);
  virtual void visit(const Parameter* o);
  virtual void visit(const Identifier<Unknown>* o);
  virtual void visit(const Identifier<Parameter>* o);
  virtual void visit(const Identifier<GlobalVariable>* o);
  virtual void visit(const Identifier<LocalVariable>* o);
  virtual void visit(const Identifier<MemberVariable>* o);
  virtual void visit(const OverloadedIdentifier<Function>* o);
  virtual void visit(const OverloadedIdentifier<Fiber>* o);
  virtual void visit(const OverloadedIdentifier<MemberFunction>* o);
  virtual void visit(const OverloadedIdentifier<MemberFiber>* o);
  virtual void visit(const OverloadedIdentifier<BinaryOperator>* o);
  virtual void visit(const OverloadedIdentifier<UnaryOperator>* o);

  virtual void visit(const File* o);
  virtual void visit(const GlobalVariable* o);
  virtual void visit(const LocalVariable* o);
  virtual void visit(const MemberVariable* o);
  virtual void visit(const Function* o);
  virtual void visit(const Fiber* o);
  virtual void visit(const MemberFunction* o);
  virtual void visit(const MemberFiber* o);
  virtual void visit(const Program* o);
  virtual void visit(const BinaryOperator* o);
  virtual void visit(const UnaryOperator* o);
  virtual void visit(const AssignmentOperator* o);
  virtual void visit(const ConversionOperator* o);
  virtual void visit(const Basic* o);
  virtual void visit(const Class* o);
  virtual void visit(const Generic* o);
  virtual void visit(const Assume* o);
  virtual void visit(const ExpressionStatement* o);
  virtual void visit(const If* o);
  virtual void visit(const For* o);
  virtual void visit(const While* o);
  virtual void visit(const DoWhile* o);
  virtual void visit(const Assert* o);
  virtual void visit(const Return* o);
  virtual void visit(const Yield* o);
  virtual void visit(const Raw* o);
  virtual void visit(const StatementList* o);

  virtual void visit(const EmptyType* o);
  virtual void visit(const ArrayType* o);
  virtual void visit(const TupleType* o);
  virtual void visit(const FunctionType* o);
  virtual void visit(const FiberType* o);
  virtual void visit(const OptionalType* o);
  virtual void visit(const ClassType* o);
  virtual void visit(const BasicType* o);
  virtual void visit(const GenericType* o);
  virtual void visit(const MemberType* o);
  virtual void visit(const UnknownType* o);
  virtual void visit(const TypeList* o);

protected:
  /**
   * Generate code for template parameters (`template<...>`).
   */
  template<class ObjectType>
  void genTemplateParams(const ObjectType* o);

  /**
   * Generate code for template arguments (`<...>`).
   */
  template<class ObjectType>
  void genTemplateArgs(const ObjectType* o);

  /**
   * Generate the initialization of a variable, including the call to the
   * constructor and/or assignment of the initial value.
   */
  template<class T>
  void genInit(const T* o);

  /**
   * Generate macro to put function call on stack trace.
   */
  void genTraceFunction(const std::string& name, const Location* loc);

  /**
   * Generate macro to update line on stack trace.
   */
  void genTraceLine(const Location* loc);

  /*
   * Generate arguments for function calls with appropriate casts where
   * necessary.
   */
  void genArgs(const Expression* args, const Type* types);
  void genLeftArg(const Call<BinaryOperator>* o);
  void genRightArg(const Call<BinaryOperator>* o);
  void genSingleArg(const Call<UnaryOperator>* o);
  void genArg(const Expression* arg, const Type* type);

  /**
   * Output header instead of source?
   */
  bool header;

  /**
   * Are we on the left side of an assignment statement?
   */
  int inAssign;

  /**
   * Are we inside a constructor?
   */
  int inConstructor;

  /**
   * Are we inside the body of a lambda function?
   */
  int inLambda;

  /**
   * Are we inside a sequence?
   */
  int inSequence;
};
}

template<class T>
void bi::CppBaseGenerator::genInit(const T* o) {
  if (o->type->isArray()) {
    ArrayType* type = dynamic_cast<ArrayType*>(o->type->canonical());
    assert(type);
    if (!o->brackets->isEmpty()) {
      if (!o->value->isEmpty()) {
        middle(" = ");
        if (o->value->type->isConvertible(*type)) {
          middle(o->value);
        } else {
          middle("libbirch::make_array_and_assign<" << type->single << ">(");
          if (!o->isValue()) {
            middle("context_, ");
          }
          middle("libbirch::make_shape(" << o->brackets << ')');
          middle(", " << o->value << ')');
        }
      } else {
        middle(" = libbirch::make_array<" << type->single << ">(");
        if (!o->isValue()) {
          middle("context_, ");
        }
        middle("libbirch::make_shape(" << o->brackets << ')');
        if (!o->args->isEmpty()) {
          middle(", " << o->args);
        }
        middle(')');
      }
    } else if (!o->value->isEmpty()) {
      middle(" = " << o->value);
    }
  } else if (o->type->isClass()) {
    if (!o->value->isEmpty()) {
      middle("(context_, " << o->value << ')');
    } else {
      middle(" = libbirch::make_pointer<" << o->type << ">(context_");
      if (!o->args->isEmpty()) {
        middle(", " << o->args);
      }
      middle(")");
    }
  } else if (!o->value->isEmpty()) {
    middle('(');
    if (!o->type->isValue()) {
      middle("context_, ");
    }
    middle(o->value << ')');
  }
}

template<class ObjectType>
void bi::CppBaseGenerator::genTemplateParams(const ObjectType* o) {
  if (o->isGeneric()) {
    start("template<");
    if (!o->isBound()) {
      for (auto iter = o->typeParams->begin(); iter != o->typeParams->end();
          ++iter) {
        if (iter != o->typeParams->begin()) {
          middle(", ");
        }
        middle("class " << *iter);
      }
    }
    finish('>');
  }
}

template<class ObjectType>
void bi::CppBaseGenerator::genTemplateArgs(const ObjectType* o) {
  if (o->isGeneric()) {
    middle('<' << o->typeParams << '>');
  }
}
<commit_msg>Fixed C++ code generation for initializing lambda function variables.<commit_after>/**
 * @file
 */
#pragma once

#include "bi/common/TypeParameterised.hpp"
#include "bi/io/indentable_ostream.hpp"

namespace bi {
/**
 * C++ code generator.
 *
 * @ingroup io
 */
class CppBaseGenerator: public indentable_ostream {
public:
  CppBaseGenerator(std::ostream& base, const int level = 0,
      const bool header = false);

  using indentable_ostream::visit;

  virtual void visit(const Name* o);

  virtual void visit(const ExpressionList* o);
  virtual void visit(const Literal<bool>* o);
  virtual void visit(const Literal<int64_t>* o);
  virtual void visit(const Literal<double>* o);
  virtual void visit(const Literal<const char*>* o);
  virtual void visit(const Parentheses* o);
  virtual void visit(const Sequence* o);
  virtual void visit(const Cast* o);
  virtual void visit(const Call<Unknown>* o);
  virtual void visit(const Call<Function>* o);
  virtual void visit(const Call<MemberFunction>* o);
  virtual void visit(const Call<Fiber>* o);
  virtual void visit(const Call<MemberFiber>* o);
  virtual void visit(const Call<Parameter>* o);
  virtual void visit(const Call<LocalVariable>* o);
  virtual void visit(const Call<MemberVariable>* o);
  virtual void visit(const Call<GlobalVariable>* o);
  virtual void visit(const Call<BinaryOperator>* o);
  virtual void visit(const Call<UnaryOperator>* o);
  virtual void visit(const Assign* o);
  virtual void visit(const Slice* o);
  virtual void visit(const Query* o);
  virtual void visit(const Get* o);
  virtual void visit(const LambdaFunction* o);
  virtual void visit(const Span* o);
  virtual void visit(const Index* o);
  virtual void visit(const Range* o);
  virtual void visit(const Member* o);
  virtual void visit(const Global* o);
  virtual void visit(const This* o);
  virtual void visit(const Super* o);
  virtual void visit(const Nil* o);
  virtual void visit(const Parameter* o);
  virtual void visit(const Identifier<Unknown>* o);
  virtual void visit(const Identifier<Parameter>* o);
  virtual void visit(const Identifier<GlobalVariable>* o);
  virtual void visit(const Identifier<LocalVariable>* o);
  virtual void visit(const Identifier<MemberVariable>* o);
  virtual void visit(const OverloadedIdentifier<Function>* o);
  virtual void visit(const OverloadedIdentifier<Fiber>* o);
  virtual void visit(const OverloadedIdentifier<MemberFunction>* o);
  virtual void visit(const OverloadedIdentifier<MemberFiber>* o);
  virtual void visit(const OverloadedIdentifier<BinaryOperator>* o);
  virtual void visit(const OverloadedIdentifier<UnaryOperator>* o);

  virtual void visit(const File* o);
  virtual void visit(const GlobalVariable* o);
  virtual void visit(const LocalVariable* o);
  virtual void visit(const MemberVariable* o);
  virtual void visit(const Function* o);
  virtual void visit(const Fiber* o);
  virtual void visit(const MemberFunction* o);
  virtual void visit(const MemberFiber* o);
  virtual void visit(const Program* o);
  virtual void visit(const BinaryOperator* o);
  virtual void visit(const UnaryOperator* o);
  virtual void visit(const AssignmentOperator* o);
  virtual void visit(const ConversionOperator* o);
  virtual void visit(const Basic* o);
  virtual void visit(const Class* o);
  virtual void visit(const Generic* o);
  virtual void visit(const Assume* o);
  virtual void visit(const ExpressionStatement* o);
  virtual void visit(const If* o);
  virtual void visit(const For* o);
  virtual void visit(const While* o);
  virtual void visit(const DoWhile* o);
  virtual void visit(const Assert* o);
  virtual void visit(const Return* o);
  virtual void visit(const Yield* o);
  virtual void visit(const Raw* o);
  virtual void visit(const StatementList* o);

  virtual void visit(const EmptyType* o);
  virtual void visit(const ArrayType* o);
  virtual void visit(const TupleType* o);
  virtual void visit(const FunctionType* o);
  virtual void visit(const FiberType* o);
  virtual void visit(const OptionalType* o);
  virtual void visit(const ClassType* o);
  virtual void visit(const BasicType* o);
  virtual void visit(const GenericType* o);
  virtual void visit(const MemberType* o);
  virtual void visit(const UnknownType* o);
  virtual void visit(const TypeList* o);

protected:
  /**
   * Generate code for template parameters (`template<...>`).
   */
  template<class ObjectType>
  void genTemplateParams(const ObjectType* o);

  /**
   * Generate code for template arguments (`<...>`).
   */
  template<class ObjectType>
  void genTemplateArgs(const ObjectType* o);

  /**
   * Generate the initialization of a variable, including the call to the
   * constructor and/or assignment of the initial value.
   */
  template<class T>
  void genInit(const T* o);

  /**
   * Generate macro to put function call on stack trace.
   */
  void genTraceFunction(const std::string& name, const Location* loc);

  /**
   * Generate macro to update line on stack trace.
   */
  void genTraceLine(const Location* loc);

  /*
   * Generate arguments for function calls with appropriate casts where
   * necessary.
   */
  void genArgs(const Expression* args, const Type* types);
  void genLeftArg(const Call<BinaryOperator>* o);
  void genRightArg(const Call<BinaryOperator>* o);
  void genSingleArg(const Call<UnaryOperator>* o);
  void genArg(const Expression* arg, const Type* type);

  /**
   * Output header instead of source?
   */
  bool header;

  /**
   * Are we on the left side of an assignment statement?
   */
  int inAssign;

  /**
   * Are we inside a constructor?
   */
  int inConstructor;

  /**
   * Are we inside the body of a lambda function?
   */
  int inLambda;

  /**
   * Are we inside a sequence?
   */
  int inSequence;
};
}

template<class T>
void bi::CppBaseGenerator::genInit(const T* o) {
  if (o->type->isArray()) {
    ArrayType* type = dynamic_cast<ArrayType*>(o->type->canonical());
    assert(type);
    if (!o->brackets->isEmpty()) {
      if (!o->value->isEmpty()) {
        middle(" = ");
        if (o->value->type->isConvertible(*type)) {
          middle(o->value);
        } else {
          middle("libbirch::make_array_and_assign<" << type->single << ">(");
          if (!o->isValue()) {
            middle("context_, ");
          }
          middle("libbirch::make_shape(" << o->brackets << ')');
          middle(", " << o->value << ')');
        }
      } else {
        middle(" = libbirch::make_array<" << type->single << ">(");
        if (!o->isValue()) {
          middle("context_, ");
        }
        middle("libbirch::make_shape(" << o->brackets << ')');
        if (!o->args->isEmpty()) {
          middle(", " << o->args);
        }
        middle(')');
      }
    } else if (!o->value->isEmpty()) {
      middle(" = " << o->value);
    }
  } else if (o->type->isClass()) {
    if (!o->value->isEmpty()) {
      middle("(context_, " << o->value << ')');
    } else {
      middle(" = libbirch::make_pointer<" << o->type << ">(context_");
      if (!o->args->isEmpty()) {
        middle(", " << o->args);
      }
      middle(")");
    }
  } else if (!o->value->isEmpty()) {
    middle('(');
    if (!o->type->isValue() && !o->type->isFunction()) {
      middle("context_, ");
    }
    middle(o->value << ')');
  }
}

template<class ObjectType>
void bi::CppBaseGenerator::genTemplateParams(const ObjectType* o) {
  if (o->isGeneric()) {
    start("template<");
    if (!o->isBound()) {
      for (auto iter = o->typeParams->begin(); iter != o->typeParams->end();
          ++iter) {
        if (iter != o->typeParams->begin()) {
          middle(", ");
        }
        middle("class " << *iter);
      }
    }
    finish('>');
  }
}

template<class ObjectType>
void bi::CppBaseGenerator::genTemplateArgs(const ObjectType* o) {
  if (o->isGeneric()) {
    middle('<' << o->typeParams << '>');
  }
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: testhelper.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: dbo $ $Date: 2001-05-08 15:55:51 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#include <stdio.h>
#include <rtl/ustrbuf.hxx>
#include <osl/diagnose.h>

#include <cppuhelper/servicefactory.hxx>
#include <com/sun/star/registry/XSimpleRegistry.hpp>
#include <com/sun/star/registry/XImplementationRegistration.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/lang/XComponent.hpp>

#include "testhelper.hxx"

using namespace rtl;
using namespace cppu;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::registry;

#if (defined UNX) || (defined OS2)
int main( int argc, char * argv[] )
#else
int __cdecl main( int argc, char * argv[] )
#endif
{
    Reference< XMultiServiceFactory > xMgr( createRegistryServiceFactory(
        OUString( RTL_CONSTASCII_USTRINGPARAM("cpputest.rdb") ) ) );

    sal_Bool bSucc = sal_False;
    try
    {
        Reference< XImplementationRegistration > xImplReg(
            xMgr->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.registry.ImplementationRegistration") ) ),
            UNO_QUERY );
        OSL_ENSURE( xImplReg.is(), "### no impl reg!" );

#ifdef UNX
#define REG_PREFIX      "lib"
#ifdef MACOSX
#define DLL_POSTFIX     ".dylib.framework"
#else
#define DLL_POSTFIX     ".so"
#endif
#else
#define REG_PREFIX      ""
#define DLL_POSTFIX     ".dll"
#endif
        OString aLibName( REG_PREFIX );
        aLibName += "corefl";
#ifndef OS2
        aLibName += DLL_POSTFIX;
#endif
        xImplReg->registerImplementation(
            OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.loader.SharedLibrary") ),
            OUString::createFromAscii( aLibName.getStr() ),
            Reference< XSimpleRegistry >() );

        testPropertyTypeHelper();
        testidlclass( xMgr );
        test_PropertySetHelper();
        test_ImplHelper( xMgr );
        test_interfacecontainer();
    }
    catch (Exception & rExc)
    {
        OSL_ENSURE( sal_False, "### exception occured!" );
        OString aMsg( OUStringToOString( rExc.Message, RTL_TEXTENCODING_ASCII_US ) );
        OSL_TRACE( "### exception occured: " );
        OSL_TRACE( aMsg.getStr() );
        OSL_TRACE( "\n" );
    }

    Reference< XComponent >( xMgr, UNO_QUERY )->dispose();

    printf( "Test finished\n" );
    return 0;
}
<commit_msg>context tests<commit_after>/*************************************************************************
 *
 *  $RCSfile: testhelper.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: dbo $ $Date: 2001-06-01 11:47:11 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#include <stdio.h>
#include <rtl/ustrbuf.hxx>
#include <osl/diagnose.h>

#include <cppuhelper/component_context.hxx>
#include <cppuhelper/servicefactory.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/registry/XSimpleRegistry.hpp>
#include <com/sun/star/registry/XImplementationRegistration.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/lang/XComponent.hpp>

#include "testhelper.hxx"

using namespace rtl;
using namespace cppu;
using namespace com::sun::star::uno;
using namespace com::sun::star;
using namespace com::sun::star::lang;
using namespace com::sun::star::registry;

#if (defined UNX) || (defined OS2)
int main( int argc, char * argv[] )
#else
int __cdecl main( int argc, char * argv[] )
#endif
{
    Reference< XMultiComponentFactory > xMgr( createRegistryServiceFactory(
        OUString( RTL_CONSTASCII_USTRINGPARAM("cpputest.rdb") ) ), UNO_QUERY );
    Reference< XComponentContext > xInitialContext;
    OSL_VERIFY( Reference< beans::XPropertySet >( xMgr, UNO_QUERY )->getPropertyValue(
        OUString( RTL_CONSTASCII_USTRINGPARAM("DefaultContext") ) ) >>= xInitialContext );

    ContextEntry_Init aEntry;
    aEntry.bLateInitService = false;
    aEntry.name = OUString( RTL_CONSTASCII_USTRINGPARAM("bla, bla") );
    aEntry.value = makeAny( (sal_Int32)5 );
    Reference< XComponentContext > xContext( createComponentContext( &aEntry, 1, xInitialContext ) );
    OSL_ASSERT( xContext->getServiceManager() == xMgr );

    sal_Bool bSucc = sal_False;
    try
    {
        Reference< XImplementationRegistration > xImplReg(
            xMgr->createInstanceWithContext(
                OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.registry.ImplementationRegistration") ),
                xContext ),
            UNO_QUERY );
        OSL_ENSURE( xImplReg.is(), "### no impl reg!" );

#ifdef UNX
#define REG_PREFIX      "lib"
#ifdef MACOSX
#define DLL_POSTFIX     ".dylib.framework"
#else
#define DLL_POSTFIX     ".so"
#endif
#else
#define REG_PREFIX      ""
#define DLL_POSTFIX     ".dll"
#endif
        OString aLibName( REG_PREFIX );
        aLibName += "corefl";
#ifndef OS2
        aLibName += DLL_POSTFIX;
#endif
        xImplReg->registerImplementation(
            OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.loader.SharedLibrary") ),
            OUString::createFromAscii( aLibName.getStr() ),
            Reference< XSimpleRegistry >() );

        Reference< XMultiServiceFactory > x( xMgr, UNO_QUERY );
        testPropertyTypeHelper();
        testidlclass( x );
        test_PropertySetHelper();
        test_ImplHelper( x );
        test_interfacecontainer();
    }
    catch (Exception & rExc)
    {
        OSL_ENSURE( sal_False, "### exception occured!" );
        OString aMsg( OUStringToOString( rExc.Message, RTL_TEXTENCODING_ASCII_US ) );
        OSL_TRACE( "### exception occured: " );
        OSL_TRACE( aMsg.getStr() );
        OSL_TRACE( "\n" );
    }

    OSL_VERIFY( xContext->getValueByName(
        OUString( RTL_CONSTASCII_USTRINGPARAM("bla, bla") ) ) == (sal_Int32)5 );
    Reference< XComponent >( xInitialContext, UNO_QUERY )->dispose();

    printf( "Test finished\n" );
    return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Bauhaus-Universitaet Weimar
// This Software is distributed under the Modified BSD License, see license.txt.
//
// Virtual Reality and Visualization Research Group
// Faculty of Media, Bauhaus-Universitaet Weimar
// http://www.uni-weimar.de/medien/vr

#include <lamure/ren/gpu_context.h>
#include <lamure/ren/model_database.h>
#include <lamure/ren/policy.h>
#include <lamure/ren/cut_database.h>
#include <lamure/ren/config.h>

namespace lamure
{
namespace ren
{

gpu_context::
gpu_context(const context_t context_id)
: context_id_(context_id),
  is_created_(false),
  temp_buffer_a_(nullptr),
  temp_buffer_b_(nullptr),
  primary_buffer_(nullptr),
  temporary_storages_(temporary_storages(nullptr, nullptr)),
  temporary_storages_provenance_(temporary_storages(nullptr, nullptr)),
  upload_budget_in_nodes_(LAMURE_DEFAULT_UPLOAD_BUDGET),
  render_budget_in_nodes_(LAMURE_DEFAULT_VIDEO_MEMORY_BUDGET) {

}

gpu_context::
~gpu_context() {
    temporary_storages_ = temporary_storages(nullptr, nullptr);
    temporary_storages_provenance_ = temporary_storages(nullptr, nullptr);

    if (temp_buffer_a_) {
        delete temp_buffer_a_;
        temp_buffer_a_ = nullptr;
    }

    if (temp_buffer_b_) {
        delete temp_buffer_b_;
        temp_buffer_b_ = nullptr;
    }

    if (primary_buffer_) {
        delete primary_buffer_;
        primary_buffer_ = nullptr;
    }

}

void gpu_context::
create(scm::gl::render_device_ptr device) {
    assert(device);
    if (is_created_) {
        return;
    }
    is_created_ = true;

    test_video_memory(device);

    model_database* database = model_database::get_instance();

    temp_buffer_a_ = new gpu_access(device, upload_budget_in_nodes_, database->get_primitives_per_node(), false);
    temp_buffer_b_ = new gpu_access(device, upload_budget_in_nodes_, database->get_primitives_per_node(), false);
    primary_buffer_ = new gpu_access(device, render_budget_in_nodes_, database->get_primitives_per_node(), true);

    map_temporary_storage(cut_database_record::temporary_buffer::BUFFER_A, device);
    map_temporary_storage(cut_database_record::temporary_buffer::BUFFER_B, device);
}

void gpu_context::
test_video_memory(scm::gl::render_device_ptr device) {
    model_database* database = model_database::get_instance();
    policy* policy = policy::get_instance();

    float safety = 0.75;
    size_t video_ram_free_in_mb = gpu_access::query_video_memory_in_mb(device) * safety;

    size_t render_budget_in_mb = policy->render_budget_in_mb();

    if(policy->out_of_core_budget_in_mb() == 0)
    {
        std::cout << "##### Total free video memory (" << video_ram_free_in_mb << " MB) will be used for the render budget #####" << std::endl;
        render_budget_in_mb = video_ram_free_in_mb;
    }
    else if(video_ram_free_in_mb < render_budget_in_mb)
    {
        std::cout << "##### The specified render budget is too large! " << video_ram_free_in_mb << " MB will be used for the render budget #####" << std::endl;
        render_budget_in_mb = video_ram_free_in_mb;
    }
    else
    {
        std::cout << "##### " << policy->render_budget_in_mb() << " MB will be used for the render budget #####" << std::endl;
    }

    long node_size_total = database->get_primitives_per_node() * sizeof(provenance_data) + database->get_slot_size();
    render_budget_in_nodes_ = (render_budget_in_mb * 1024 * 1024) / node_size_total;
    // std::cout << "RENDER1: " << render_budget_in_mb << std::endl;
    // std::cout << "RENDER1: " << render_budget_in_mb * 0.75 << std::endl;
    // std::cout << "RENDER1: " << node_size_total << std::endl;
    // std::cout << "RENDER1: " << (render_budget_in_mb * 0.75) / node_size_total << std::endl;
    // std::cout << "RENDER1: " << render_budget_in_nodes_ << std::endl;

    // render_budget_in_mb = policy->render_budget_in_mb();

    // // render_budget_in_mb = render_budget_in_mb < LAMURE_MIN_VIDEO_MEMORY_BUDGET ? LAMURE_MIN_VIDEO_MEMORY_BUDGET : render_budget_in_mb;
    // render_budget_in_mb = render_budget_in_mb > video_ram_free_in_mb * 0.75 ? video_ram_free_in_mb * 0.75 : render_budget_in_mb;

    // render_budget_in_nodes_ = (render_budget_in_mb * 1024u * 1024u) / (database->get_primitives_per_node() * sizeof(provenance_data) + database->get_slot_size());
    // std::cout << "RENDER2: " << render_budget_in_nodes_ << std::endl;

    size_t max_upload_budget_in_mb = policy->max_upload_budget_in_mb();
    max_upload_budget_in_mb = max_upload_budget_in_mb < LAMURE_MIN_UPLOAD_BUDGET ? LAMURE_MIN_UPLOAD_BUDGET : max_upload_budget_in_mb;
    max_upload_budget_in_mb = max_upload_budget_in_mb > video_ram_free_in_mb * 0.125 ? video_ram_free_in_mb * 0.125 : max_upload_budget_in_mb;
    size_t max_upload_budget_in_nodes = (max_upload_budget_in_mb * 1024u * 1024u) / database->get_slot_size();
    upload_budget_in_nodes_ = max_upload_budget_in_nodes;

#if 1
   // upload_budget_in_nodes_ = max_upload_budget_in_nodes/4;

#else
    gpu_access* test_temp = new gpu_access(device, 1, database->surfels_per_node(), false);
    gpu_access* test_main = new gpu_access(device, 1, database->surfels_per_node(), true);
    LodPointCloud::serializedsurfel* node_data = (LodPointCloud::serializedsurfel*)new char[size_of_node_in_bytes];
    memset((char*)node_data, 0, size_of_node_in_bytes);
    char* mapped_temp = test_temp->map(device);
    memcpy(mapped_temp, node_data, size_of_node_in_bytes);
    test_temp->unmap(device);

    auto frame_duration_in_ns = boost::timer::nanosecond_type(16.0 * 1000 * 1000);

    boost::timer::cpu_timer upload_timer;

    unsigned int iteration = 0;
    while (true) {

        upload_timer.start();

        for (unsigned int i = 0; i < upload_budget_in_nodes_; ++i) {
            size_t offset_in_temp_VBO = 0;
            size_t offset_in_render_VBO = 0;
            device->main_context()->copy_buffer_data(test_main->buffer(), test_temp->buffer(), offset_in_render_VBO, offset_in_temp_VBO, size_of_node_in_bytes);
        }

        upload_timer.stop();

        boost::timer::cpu_times const elapsed(upload_timer.elapsed());
        boost::timer::nanosecond_type const elapsed_ns(elapsed.system + elapsed.user);

        if (iteration++ > 1) {
            if (elapsed_ns < frame_duration_in_ns) {
                if (upload_budget_in_nodes_ < max_upload_budget_in_nodes) {
                    ++upload_budget_in_nodes_;
                }
                else {
                    break;
                }
            }
            else {
                break;
            }
        }

    }

    delete test_temp;
    delete test_main;
    delete[] node_data;

    device->main_context()->apply();
#endif

#ifdef LAMURE_ENABLE_INFO
    std::cout << "lamure: context " << context_id_ << " render budget (MB): " << render_budget_in_mb << std::endl;
    std::cout << "lamure: context " << context_id_ << " upload budget (MB): " << max_upload_budget_in_mb << std::endl;
#endif

}

scm::gl::buffer_ptr gpu_context::
get_context_buffer(scm::gl::render_device_ptr device) {
    if (!is_created_)
        create(device);

    assert(device);

    return primary_buffer_->get_buffer();
}

scm::gl::vertex_array_ptr gpu_context::
get_context_memory(bvh::primitive_type type, scm::gl::render_device_ptr device) {
    if (!is_created_)
        create(device);

    assert(device);

    return primary_buffer_->get_memory(type);
}

void gpu_context::
map_temporary_storage(const cut_database_record::temporary_buffer& buffer, scm::gl::render_device_ptr device) {
    if (!is_created_)
        create(device);

    assert(device);

    switch (buffer) {
        case cut_database_record::temporary_buffer::BUFFER_A:
            if (!temp_buffer_a_->is_mapped()) {
                temporary_storages_.storage_a_ = temp_buffer_a_->map(device);
                temporary_storages_provenance_.storage_a_ = temp_buffer_a_->map_provenance(device);
            }
            return;
            break;

        case cut_database_record::temporary_buffer::BUFFER_B:
            if (!temp_buffer_b_->is_mapped()) {
                temporary_storages_.storage_b_ = temp_buffer_b_->map(device);
                temporary_storages_provenance_.storage_b_ = temp_buffer_b_->map_provenance(device);
            }
            return;
            break;

        default: break;
    }

    throw std::runtime_error(
       "lamure: Failed to map temporary buffer on context: " + context_id_);

}

void gpu_context::
unmap_temporary_storage(const cut_database_record::temporary_buffer& buffer, scm::gl::render_device_ptr device) {
    if (!is_created_)
        create(device);

    assert(device);

    switch (buffer) {
        case cut_database_record::temporary_buffer::BUFFER_A:
            if (temp_buffer_a_->is_mapped()) {
                temp_buffer_a_->unmap(device);
                temp_buffer_a_->unmap_provenance(device);
            }
            break;

        case cut_database_record::temporary_buffer::BUFFER_B:
            if (temp_buffer_b_->is_mapped()) {
                temp_buffer_b_->unmap(device);
                temp_buffer_b_->unmap_provenance(device);
            }
            break;

        default: break;
    }
}

//returns true if any node has been uploaded; false otherwise
bool gpu_context::
update_primary_buffer(const cut_database_record::temporary_buffer& from_buffer, scm::gl::render_device_ptr device) {
    if (!is_created_)
        create(device);

    assert(device);

    model_database* database = model_database::get_instance();

    cut_database* cuts = cut_database::get_instance();

    size_t uploaded_nodes = 0;

    switch (from_buffer) {
        case cut_database_record::temporary_buffer::BUFFER_A:
        {
            if (temp_buffer_a_->is_mapped()) {
                throw std::runtime_error(
                   "lamure: gpu_context::Failed to transfer nodes into main memory on context: " + context_id_);
            }
            std::vector<cut_database_record::slot_update_desc>& transfer_descr_list = cuts->get_updated_set(context_id_);
            if (!transfer_descr_list.empty()) {
                uploaded_nodes += transfer_descr_list.size();

                for (const auto& transfer_desc : transfer_descr_list)
                {
                    size_t offset_in_temp_VBO = transfer_desc.src_ * database->get_slot_size();
                    size_t offset_in_render_VBO = transfer_desc.dst_ * database->get_slot_size();
                    device->main_context()->copy_buffer_data(
                        primary_buffer_->get_buffer(),
                        temp_buffer_a_->get_buffer(),
                        offset_in_render_VBO,
                        offset_in_temp_VBO,
                        database->get_slot_size()
                    );

                    size_t offset_in_temp_VBO_provenance = transfer_desc.src_ * database->get_primitives_per_node() * sizeof(provenance_data);
                    size_t offset_in_render_VBO_provenance = transfer_desc.dst_ * database->get_primitives_per_node() * sizeof(provenance_data);
                    device->main_context()->copy_buffer_data(
                        primary_buffer_->get_buffer_provenance(),
                        temp_buffer_a_->get_buffer_provenance(),
                        offset_in_render_VBO_provenance,
                        offset_in_temp_VBO_provenance,
                        database->get_primitives_per_node() * sizeof(provenance_data)
                    );
                }
            }
            break;
        }

        case cut_database_record::temporary_buffer::BUFFER_B:
        {
            if (temp_buffer_b_->is_mapped()) {
                throw std::runtime_error(
                   "lamure: gpu_context::Failed to transfer nodes into main memory on context: " + context_id_);
            }
            std::vector<cut_database_record::slot_update_desc>& transfer_descr_list = cuts->get_updated_set(context_id_);
            if (!transfer_descr_list.empty()) {
                uploaded_nodes += transfer_descr_list.size();

                for (const auto& transfer_desc : transfer_descr_list) {
                    size_t offset_in_temp_VBO = transfer_desc.src_ * database->get_slot_size();
                    size_t offset_in_render_VBO = transfer_desc.dst_ * database->get_slot_size();
                    device->main_context()->copy_buffer_data(
                        primary_buffer_->get_buffer(),
                        temp_buffer_b_->get_buffer(),
                        offset_in_render_VBO,
                        offset_in_temp_VBO,
                        database->get_slot_size()
                    );

                    size_t offset_in_temp_VBO_provenance = transfer_desc.src_ * database->get_primitives_per_node() * sizeof(provenance_data);
                    size_t offset_in_render_VBO_provenance = transfer_desc.dst_ * database->get_primitives_per_node() * sizeof(provenance_data);
                    device->main_context()->copy_buffer_data(
                        primary_buffer_->get_buffer_provenance(),
                        temp_buffer_b_->get_buffer_provenance(),
                        offset_in_render_VBO_provenance,
                        offset_in_temp_VBO_provenance,
                        database->get_primitives_per_node() * sizeof(provenance_data)
                    );
                }
            }
            break;
        }
        default: break;

    }

    return uploaded_nodes != 0;
}

}
}
<commit_msg>*improved budget-usage<commit_after>// Copyright (c) 2014 Bauhaus-Universitaet Weimar
// This Software is distributed under the Modified BSD License, see license.txt.
//
// Virtual Reality and Visualization Research Group
// Faculty of Media, Bauhaus-Universitaet Weimar
// http://www.uni-weimar.de/medien/vr

#include <lamure/ren/gpu_context.h>
#include <lamure/ren/model_database.h>
#include <lamure/ren/policy.h>
#include <lamure/ren/cut_database.h>
#include <lamure/ren/config.h>

namespace lamure
{
namespace ren
{

gpu_context::
gpu_context(const context_t context_id)
: context_id_(context_id),
  is_created_(false),
  temp_buffer_a_(nullptr),
  temp_buffer_b_(nullptr),
  primary_buffer_(nullptr),
  temporary_storages_(temporary_storages(nullptr, nullptr)),
  temporary_storages_provenance_(temporary_storages(nullptr, nullptr)),
  upload_budget_in_nodes_(LAMURE_DEFAULT_UPLOAD_BUDGET),
  render_budget_in_nodes_(LAMURE_DEFAULT_VIDEO_MEMORY_BUDGET) {

}

gpu_context::
~gpu_context() {
    temporary_storages_ = temporary_storages(nullptr, nullptr);
    temporary_storages_provenance_ = temporary_storages(nullptr, nullptr);

    if (temp_buffer_a_) {
        delete temp_buffer_a_;
        temp_buffer_a_ = nullptr;
    }

    if (temp_buffer_b_) {
        delete temp_buffer_b_;
        temp_buffer_b_ = nullptr;
    }

    if (primary_buffer_) {
        delete primary_buffer_;
        primary_buffer_ = nullptr;
    }

}

void gpu_context::
create(scm::gl::render_device_ptr device) {
    assert(device);
    if (is_created_) {
        return;
    }
    is_created_ = true;

    test_video_memory(device);

    model_database* database = model_database::get_instance();

    temp_buffer_a_ = new gpu_access(device, upload_budget_in_nodes_, database->get_primitives_per_node(), false);
    temp_buffer_b_ = new gpu_access(device, upload_budget_in_nodes_, database->get_primitives_per_node(), false);
    primary_buffer_ = new gpu_access(device, render_budget_in_nodes_, database->get_primitives_per_node(), true);

    map_temporary_storage(cut_database_record::temporary_buffer::BUFFER_A, device);
    map_temporary_storage(cut_database_record::temporary_buffer::BUFFER_B, device);
}

void gpu_context::
test_video_memory(scm::gl::render_device_ptr device) {
    model_database* database = model_database::get_instance();
    policy* policy = policy::get_instance();

    float safety = 0.75;
    size_t video_ram_free_in_mb = gpu_access::query_video_memory_in_mb(device) * safety;

    size_t render_budget_in_mb = policy->render_budget_in_mb();

    if(policy->out_of_core_budget_in_mb() == 0)
    {
        std::cout << "##### Total free video memory (" << video_ram_free_in_mb << " MB) will be used for the render budget #####" << std::endl;
        render_budget_in_mb = video_ram_free_in_mb;
    }
    else if(video_ram_free_in_mb < render_budget_in_mb)
    {
        std::cout << "##### The specified render budget is too large! " << video_ram_free_in_mb << " MB will be used for the render budget #####" << std::endl;
        render_budget_in_mb = video_ram_free_in_mb;
    }
    else
    {
        std::cout << "##### " << policy->render_budget_in_mb() << " MB will be used for the render budget #####" << std::endl;
    }

    long node_size_total = database->get_primitives_per_node() * sizeof(provenance_data) + database->get_slot_size();
    render_budget_in_nodes_ = (render_budget_in_mb * 1024 * 1024) / node_size_total;

    // render_budget_in_mb = policy->render_budget_in_mb();

    // // render_budget_in_mb = render_budget_in_mb < LAMURE_MIN_VIDEO_MEMORY_BUDGET ? LAMURE_MIN_VIDEO_MEMORY_BUDGET : render_budget_in_mb;
    // render_budget_in_mb = render_budget_in_mb > video_ram_free_in_mb * 0.75 ? video_ram_free_in_mb * 0.75 : render_budget_in_mb;

    // render_budget_in_nodes_ = (render_budget_in_mb * 1024u * 1024u) / (database->get_primitives_per_node() * sizeof(provenance_data) + database->get_slot_size());
    // std::cout << "RENDER2: " << render_budget_in_nodes_ << std::endl;

    size_t max_upload_budget_in_mb = policy->max_upload_budget_in_mb();
    max_upload_budget_in_mb = max_upload_budget_in_mb < LAMURE_MIN_UPLOAD_BUDGET ? LAMURE_MIN_UPLOAD_BUDGET : max_upload_budget_in_mb;
    max_upload_budget_in_mb = max_upload_budget_in_mb > video_ram_free_in_mb * 0.125 ? video_ram_free_in_mb * 0.125 : max_upload_budget_in_mb;

    upload_budget_in_nodes_ = (max_upload_budget_in_mb * 1024u * 1024u) / node_size_total;

#if 1
   // upload_budget_in_nodes_ = max_upload_budget_in_nodes/4;

#else
    gpu_access* test_temp = new gpu_access(device, 1, database->surfels_per_node(), false);
    gpu_access* test_main = new gpu_access(device, 1, database->surfels_per_node(), true);
    LodPointCloud::serializedsurfel* node_data = (LodPointCloud::serializedsurfel*)new char[size_of_node_in_bytes];
    memset((char*)node_data, 0, size_of_node_in_bytes);
    char* mapped_temp = test_temp->map(device);
    memcpy(mapped_temp, node_data, size_of_node_in_bytes);
    test_temp->unmap(device);

    auto frame_duration_in_ns = boost::timer::nanosecond_type(16.0 * 1000 * 1000);

    boost::timer::cpu_timer upload_timer;

    unsigned int iteration = 0;
    while (true) {

        upload_timer.start();

        for (unsigned int i = 0; i < upload_budget_in_nodes_; ++i) {
            size_t offset_in_temp_VBO = 0;
            size_t offset_in_render_VBO = 0;
            device->main_context()->copy_buffer_data(test_main->buffer(), test_temp->buffer(), offset_in_render_VBO, offset_in_temp_VBO, size_of_node_in_bytes);
        }

        upload_timer.stop();

        boost::timer::cpu_times const elapsed(upload_timer.elapsed());
        boost::timer::nanosecond_type const elapsed_ns(elapsed.system + elapsed.user);

        if (iteration++ > 1) {
            if (elapsed_ns < frame_duration_in_ns) {
                if (upload_budget_in_nodes_ < max_upload_budget_in_nodes) {
                    ++upload_budget_in_nodes_;
                }
                else {
                    break;
                }
            }
            else {
                break;
            }
        }

    }

    delete test_temp;
    delete test_main;
    delete[] node_data;

    device->main_context()->apply();
#endif

#ifdef LAMURE_ENABLE_INFO
    std::cout << "lamure: context " << context_id_ << " render budget (MB): " << render_budget_in_mb << std::endl;
    std::cout << "lamure: context " << context_id_ << " upload budget (MB): " << max_upload_budget_in_mb << std::endl;
#endif

}

scm::gl::buffer_ptr gpu_context::
get_context_buffer(scm::gl::render_device_ptr device) {
    if (!is_created_)
        create(device);

    assert(device);

    return primary_buffer_->get_buffer();
}

scm::gl::vertex_array_ptr gpu_context::
get_context_memory(bvh::primitive_type type, scm::gl::render_device_ptr device) {
    if (!is_created_)
        create(device);

    assert(device);

    return primary_buffer_->get_memory(type);
}

void gpu_context::
map_temporary_storage(const cut_database_record::temporary_buffer& buffer, scm::gl::render_device_ptr device) {
    if (!is_created_)
        create(device);

    assert(device);

    switch (buffer) {
        case cut_database_record::temporary_buffer::BUFFER_A:
            if (!temp_buffer_a_->is_mapped()) {
                temporary_storages_.storage_a_ = temp_buffer_a_->map(device);
                temporary_storages_provenance_.storage_a_ = temp_buffer_a_->map_provenance(device);
            }
            return;
            break;

        case cut_database_record::temporary_buffer::BUFFER_B:
            if (!temp_buffer_b_->is_mapped()) {
                temporary_storages_.storage_b_ = temp_buffer_b_->map(device);
                temporary_storages_provenance_.storage_b_ = temp_buffer_b_->map_provenance(device);
            }
            return;
            break;

        default: break;
    }

    throw std::runtime_error(
       "lamure: Failed to map temporary buffer on context: " + context_id_);

}

void gpu_context::
unmap_temporary_storage(const cut_database_record::temporary_buffer& buffer, scm::gl::render_device_ptr device) {
    if (!is_created_)
        create(device);

    assert(device);

    switch (buffer) {
        case cut_database_record::temporary_buffer::BUFFER_A:
            if (temp_buffer_a_->is_mapped()) {
                temp_buffer_a_->unmap(device);
                temp_buffer_a_->unmap_provenance(device);
            }
            break;

        case cut_database_record::temporary_buffer::BUFFER_B:
            if (temp_buffer_b_->is_mapped()) {
                temp_buffer_b_->unmap(device);
                temp_buffer_b_->unmap_provenance(device);
            }
            break;

        default: break;
    }
}

//returns true if any node has been uploaded; false otherwise
bool gpu_context::
update_primary_buffer(const cut_database_record::temporary_buffer& from_buffer, scm::gl::render_device_ptr device) {
    if (!is_created_)
        create(device);

    assert(device);

    model_database* database = model_database::get_instance();

    cut_database* cuts = cut_database::get_instance();

    size_t uploaded_nodes = 0;

    switch (from_buffer) {
        case cut_database_record::temporary_buffer::BUFFER_A:
        {
            if (temp_buffer_a_->is_mapped()) {
                throw std::runtime_error(
                   "lamure: gpu_context::Failed to transfer nodes into main memory on context: " + context_id_);
            }
            std::vector<cut_database_record::slot_update_desc>& transfer_descr_list = cuts->get_updated_set(context_id_);
            if (!transfer_descr_list.empty()) {
                uploaded_nodes += transfer_descr_list.size();

                for (const auto& transfer_desc : transfer_descr_list)
                {
                    size_t offset_in_temp_VBO = transfer_desc.src_ * database->get_slot_size();
                    size_t offset_in_render_VBO = transfer_desc.dst_ * database->get_slot_size();
                    device->main_context()->copy_buffer_data(
                        primary_buffer_->get_buffer(),
                        temp_buffer_a_->get_buffer(),
                        offset_in_render_VBO,
                        offset_in_temp_VBO,
                        database->get_slot_size()
                    );

                    size_t offset_in_temp_VBO_provenance = transfer_desc.src_ * database->get_primitives_per_node() * sizeof(provenance_data);
                    size_t offset_in_render_VBO_provenance = transfer_desc.dst_ * database->get_primitives_per_node() * sizeof(provenance_data);
                    device->main_context()->copy_buffer_data(
                        primary_buffer_->get_buffer_provenance(),
                        temp_buffer_a_->get_buffer_provenance(),
                        offset_in_render_VBO_provenance,
                        offset_in_temp_VBO_provenance,
                        database->get_primitives_per_node() * sizeof(provenance_data)
                    );
                }
            }
            break;
        }

        case cut_database_record::temporary_buffer::BUFFER_B:
        {
            if (temp_buffer_b_->is_mapped()) {
                throw std::runtime_error(
                   "lamure: gpu_context::Failed to transfer nodes into main memory on context: " + context_id_);
            }
            std::vector<cut_database_record::slot_update_desc>& transfer_descr_list = cuts->get_updated_set(context_id_);
            if (!transfer_descr_list.empty()) {
                uploaded_nodes += transfer_descr_list.size();

                for (const auto& transfer_desc : transfer_descr_list) {
                    size_t offset_in_temp_VBO = transfer_desc.src_ * database->get_slot_size();
                    size_t offset_in_render_VBO = transfer_desc.dst_ * database->get_slot_size();
                    device->main_context()->copy_buffer_data(
                        primary_buffer_->get_buffer(),
                        temp_buffer_b_->get_buffer(),
                        offset_in_render_VBO,
                        offset_in_temp_VBO,
                        database->get_slot_size()
                    );

                    size_t offset_in_temp_VBO_provenance = transfer_desc.src_ * database->get_primitives_per_node() * sizeof(provenance_data);
                    size_t offset_in_render_VBO_provenance = transfer_desc.dst_ * database->get_primitives_per_node() * sizeof(provenance_data);
                    device->main_context()->copy_buffer_data(
                        primary_buffer_->get_buffer_provenance(),
                        temp_buffer_b_->get_buffer_provenance(),
                        offset_in_render_VBO_provenance,
                        offset_in_temp_VBO_provenance,
                        database->get_primitives_per_node() * sizeof(provenance_data)
                    );
                }
            }
            break;
        }
        default: break;

    }

    return uploaded_nodes != 0;
}

}
}
<|endoftext|>


<commit_before>#include "libtorrent/session.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/hasher.hpp"
#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/operations.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"

using boost::filesystem::remove_all;

void test_swarm()
{
	using namespace libtorrent;

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48000, 49000));
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49000, 50000));
	session ses3(fingerprint("LT", 0, 1, 0, 0), std::make_pair(50000, 51000));

	// this is to avoid everything finish from a single peer
	// immediately. To make the swarm actually connect all
	// three peers before finishing.
	float rate_limit = 40000;
	ses1.set_upload_rate_limit(int(rate_limit));
	ses2.set_download_rate_limit(int(rate_limit));
	ses3.set_download_rate_limit(int(rate_limit));
	ses2.set_upload_rate_limit(int(rate_limit / 2));
	ses3.set_upload_rate_limit(int(rate_limit / 2));

	session_settings settings;
	settings.allow_multiple_connections_per_ip = true;
	ses1.set_settings(settings);
	ses2.set_settings(settings);
	ses3.set_settings(settings);

#ifndef TORRENT_DISABLE_ENCRYPTION
	pe_settings pes;
	pes.out_enc_policy = pe_settings::disabled;
	pes.in_enc_policy = pe_settings::disabled;
	ses1.set_pe_settings(pes);
	ses2.set_pe_settings(pes);
	ses3.set_pe_settings(pes);
#endif

	torrent_handle tor1;
	torrent_handle tor2;
	torrent_handle tor3;

	boost::tie(tor1, tor2, tor3) = setup_transfer(&ses1, &ses2, &ses3, true, false);

	float sum_dl_rate2 = 0.f;
	float sum_dl_rate3 = 0.f;
	int count_dl_rates2 = 0;
	int count_dl_rates3 = 0;

	for (int i = 0; i < 65; ++i)
	{
		std::auto_ptr<alert> a;
		a = ses1.pop_alert();
		if (a.get())
			std::cerr << "ses1: " << a->msg() << "\n";

		a = ses2.pop_alert();
		if (a.get())
			std::cerr << "ses2: " << a->msg() << "\n";

		a = ses3.pop_alert();
		if (a.get())
			std::cerr << "ses3: " << a->msg() << "\n";

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();
		torrent_status st3 = tor3.status();

		if (st2.progress < 1.f && st2.progress > 0.3f)
		{
			sum_dl_rate2 += st2.download_payload_rate;
			++count_dl_rates2;
		}
		if (st3.progress < 1.f && st3.progress > 0.3f)
		{
			sum_dl_rate3 += st3.download_rate;
			++count_dl_rates3;
		}

		std::cerr
			<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s: "
			<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st2.progress * 100) << "% - "
			<< "\033[32m" << int(st3.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[31m" << int(st3.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st3.progress * 100) << "% "
			<< std::endl;

		if (tor2.is_seed() && tor3.is_seed()) break;
		test_sleep(1000);
	}

	TEST_CHECK(tor2.is_seed());
	TEST_CHECK(tor3.is_seed());

	float average2 = sum_dl_rate2 / float(count_dl_rates2);
	float average3 = sum_dl_rate3 / float(count_dl_rates3);

	std::cerr << "average rate: " << (average2 / 1000.f) << "kB/s - "
		<< (average3 / 1000.f) << "kB/s" << std::endl;

	TEST_CHECK(std::fabs(average2 - float(rate_limit)) < 3000.f);
	TEST_CHECK(std::fabs(average3 - float(rate_limit)) < 3000.f);
	if (tor2.is_seed() && tor3.is_seed()) std::cerr << "done\n";
}

int test_main()
{
	using namespace libtorrent;
	using namespace boost::filesystem;

	// in case the previous run was terminated
	try { remove_all("./tmp1"); } catch (std::exception&) {}
	try { remove_all("./tmp2"); } catch (std::exception&) {}
	try { remove_all("./tmp3"); } catch (std::exception&) {}

	test_swarm();

	remove_all("./tmp1");
	remove_all("./tmp2");
	remove_all("./tmp3");

	return 0;
}

<commit_msg>more output in test_swarm<commit_after>#include "libtorrent/session.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/hasher.hpp"
#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/operations.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"

using boost::filesystem::remove_all;

void test_swarm()
{
	using namespace libtorrent;

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48000, 49000));
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49000, 50000));
	session ses3(fingerprint("LT", 0, 1, 0, 0), std::make_pair(50000, 51000));

	// this is to avoid everything finish from a single peer
	// immediately. To make the swarm actually connect all
	// three peers before finishing.
	float rate_limit = 40000;
	ses1.set_upload_rate_limit(int(rate_limit));
	ses2.set_download_rate_limit(int(rate_limit));
	ses3.set_download_rate_limit(int(rate_limit));
	ses2.set_upload_rate_limit(int(rate_limit / 2));
	ses3.set_upload_rate_limit(int(rate_limit / 2));

	session_settings settings;
	settings.allow_multiple_connections_per_ip = true;
	ses1.set_settings(settings);
	ses2.set_settings(settings);
	ses3.set_settings(settings);

#ifndef TORRENT_DISABLE_ENCRYPTION
	pe_settings pes;
	pes.out_enc_policy = pe_settings::disabled;
	pes.in_enc_policy = pe_settings::disabled;
	ses1.set_pe_settings(pes);
	ses2.set_pe_settings(pes);
	ses3.set_pe_settings(pes);
#endif

	torrent_handle tor1;
	torrent_handle tor2;
	torrent_handle tor3;

	boost::tie(tor1, tor2, tor3) = setup_transfer(&ses1, &ses2, &ses3, true, false);

	float sum_dl_rate2 = 0.f;
	float sum_dl_rate3 = 0.f;
	int count_dl_rates2 = 0;
	int count_dl_rates3 = 0;

	for (int i = 0; i < 65; ++i)
	{
		std::auto_ptr<alert> a;
		a = ses1.pop_alert();
		if (a.get())
			std::cerr << "ses1: " << a->msg() << "\n";

		a = ses2.pop_alert();
		if (a.get())
			std::cerr << "ses2: " << a->msg() << "\n";

		a = ses3.pop_alert();
		if (a.get())
			std::cerr << "ses3: " << a->msg() << "\n";

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();
		torrent_status st3 = tor3.status();

		if (st2.progress < 1.f && st2.progress > 0.3f)
		{
			sum_dl_rate2 += st2.download_payload_rate;
			++count_dl_rates2;
		}
		if (st3.progress < 1.f && st3.progress > 0.3f)
		{
			sum_dl_rate3 += st3.download_rate;
			++count_dl_rates3;
		}

		std::cerr
			<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s "
			<< st1.num_peers << ": "
			<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st2.progress * 100) << "% "
			<< st2.num_peers << " - "
			<< "\033[32m" << int(st3.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[31m" << int(st3.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st3.progress * 100) << "% "
			<< st3.num_peers
			<< std::endl;

		if (tor2.is_seed() && tor3.is_seed()) break;
		test_sleep(1000);
	}

	TEST_CHECK(tor2.is_seed());
	TEST_CHECK(tor3.is_seed());

	float average2 = sum_dl_rate2 / float(count_dl_rates2);
	float average3 = sum_dl_rate3 / float(count_dl_rates3);

	std::cerr << "average rate: " << (average2 / 1000.f) << "kB/s - "
		<< (average3 / 1000.f) << "kB/s" << std::endl;

	TEST_CHECK(std::fabs(average2 - float(rate_limit)) < 3000.f);
	TEST_CHECK(std::fabs(average3 - float(rate_limit)) < 3000.f);
	if (tor2.is_seed() && tor3.is_seed()) std::cerr << "done\n";
}

int test_main()
{
	using namespace libtorrent;
	using namespace boost::filesystem;

	// in case the previous run was terminated
	try { remove_all("./tmp1"); } catch (std::exception&) {}
	try { remove_all("./tmp2"); } catch (std::exception&) {}
	try { remove_all("./tmp3"); } catch (std::exception&) {}

	test_swarm();

	remove_all("./tmp1");
	remove_all("./tmp2");
	remove_all("./tmp3");

	return 0;
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/session.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/alert_types.hpp"
#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/operations.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"

using boost::filesystem::remove_all;
using boost::filesystem::exists;

void test_swarm()
{
	using namespace libtorrent;

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48000, 49000));
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49000, 50000));
	session ses3(fingerprint("LT", 0, 1, 0, 0), std::make_pair(50000, 51000));

	// this is to avoid everything finish from a single peer
	// immediately. To make the swarm actually connect all
	// three peers before finishing.
	float rate_limit = 100000;
	ses1.set_upload_rate_limit(int(rate_limit));
	ses2.set_download_rate_limit(int(rate_limit));
	ses3.set_download_rate_limit(int(rate_limit));
	ses2.set_upload_rate_limit(int(rate_limit / 2));
	ses3.set_upload_rate_limit(int(rate_limit / 2));

	session_settings settings;
	settings.allow_multiple_connections_per_ip = true;
	settings.ignore_limits_on_local_network = false;
	ses1.set_settings(settings);
	ses2.set_settings(settings);
	ses3.set_settings(settings);

#ifndef TORRENT_DISABLE_ENCRYPTION
	pe_settings pes;
	pes.out_enc_policy = pe_settings::forced;
	pes.in_enc_policy = pe_settings::forced;
	ses1.set_pe_settings(pes);
	ses2.set_pe_settings(pes);
	ses3.set_pe_settings(pes);
#endif

	torrent_handle tor1;
	torrent_handle tor2;
	torrent_handle tor3;

	// test using piece sizes smaller than 16kB
	boost::tie(tor1, tor2, tor3) = setup_transfer(&ses1, &ses2, &ses3, true, false, true, "_swarm", 8 * 1024);

	ses1.set_alert_mask(alert::all_categories & ~alert::progress_notification);
	ses2.set_alert_mask(alert::all_categories & ~alert::progress_notification);
	ses3.set_alert_mask(alert::all_categories & ~alert::progress_notification);

	float sum_dl_rate2 = 0.f;
	float sum_dl_rate3 = 0.f;
	int count_dl_rates2 = 0;
	int count_dl_rates3 = 0;

	for (int i = 0; i < 30; ++i)
	{
		print_alerts(ses1, "ses1");
		print_alerts(ses2, "ses2");
		print_alerts(ses3, "ses3");

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();
		torrent_status st3 = tor3.status();

		if (st2.progress < 1.f && st2.progress > 0.5f)
		{
			sum_dl_rate2 += st2.download_payload_rate;
			++count_dl_rates2;
		}
		if (st3.progress < 1.f && st3.progress > 0.5f)
		{
			sum_dl_rate3 += st3.download_rate;
			++count_dl_rates3;
		}

		std::cerr
			<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s "
			<< st1.num_peers << ": "
			<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st2.progress * 100) << "% "
			<< st2.num_peers << " - "
			<< "\033[32m" << int(st3.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[31m" << int(st3.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st3.progress * 100) << "% "
			<< st3.num_peers
			<< std::endl;

		if (tor2.is_seed() && tor3.is_seed()) break;
		test_sleep(1000);
	}

	TEST_CHECK(tor2.is_seed());
	TEST_CHECK(tor3.is_seed());

	float average2 = sum_dl_rate2 / float(count_dl_rates2);
	float average3 = sum_dl_rate3 / float(count_dl_rates3);

	std::cerr << average2 << std::endl;
	std::cerr << "average rate: " << (average2 / 1000.f) << "kB/s - "
		<< (average3 / 1000.f) << "kB/s" << std::endl;

	TEST_CHECK(std::fabs(average2 - float(rate_limit)) < rate_limit / 11.f);
	TEST_CHECK(std::fabs(average3 - float(rate_limit)) < rate_limit / 11.f);
	if (tor2.is_seed() && tor3.is_seed()) std::cerr << "done\n";

	// make sure the files are deleted
	ses1.remove_torrent(tor1, session::delete_files);
	ses2.remove_torrent(tor2, session::delete_files);
	ses3.remove_torrent(tor3, session::delete_files);

	std::auto_ptr<alert> a = ses1.pop_alert();
	ptime end = time_now() + seconds(20);
	while (a.get() == 0 || dynamic_cast<torrent_deleted_alert*>(a.get()) == 0)
	{
		if (ses1.wait_for_alert(end - time_now()) == 0)
		{
			std::cerr << "wait_for_alert() expired" << std::endl;
			break;
		}
		a = ses1.pop_alert();
		assert(a.get());
		std::cerr << a->message() << std::endl;
	}

	TEST_CHECK(dynamic_cast<torrent_deleted_alert*>(a.get()) != 0);

	// there shouldn't be any alerts generated from now on
	// make sure that the timer in wait_for_alert() works
	// this should time out (ret == 0) and it should take
	// about 2 seconds
	ptime start = time_now();
	alert const* ret = ses1.wait_for_alert(seconds(2));
	TEST_CHECK(ret == 0);
	if (ret != 0) std::cerr << ret->message() << std::endl;
	TEST_CHECK(time_now() - start < seconds(3));
	TEST_CHECK(time_now() - start > seconds(2));
}

int test_main()
{
	using namespace libtorrent;
	using namespace boost::filesystem;

	// in case the previous run was terminated
	try { remove_all("./tmp1_swarm"); } catch (std::exception&) {}
	try { remove_all("./tmp2_swarm"); } catch (std::exception&) {}
	try { remove_all("./tmp3_swarm"); } catch (std::exception&) {}

	test_swarm();

	test_sleep(2000);
	TEST_CHECK(!exists("./tmp1_swarm/temporary"));
	TEST_CHECK(!exists("./tmp2_swarm/temporary"));
	TEST_CHECK(!exists("./tmp3_swarm/temporary"));

	remove_all("./tmp1_swarm");
	remove_all("./tmp2_swarm");
	remove_all("./tmp3_swarm");

	return 0;
}

<commit_msg>fixed test_swarm<commit_after>/*

Copyright (c) 2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/session.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/alert_types.hpp"
#include <boost/thread.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/operations.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"

using boost::filesystem::remove_all;
using boost::filesystem::exists;

void test_swarm()
{
	using namespace libtorrent;

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48000, 49000));
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49000, 50000));
	session ses3(fingerprint("LT", 0, 1, 0, 0), std::make_pair(50000, 51000));

	// this is to avoid everything finish from a single peer
	// immediately. To make the swarm actually connect all
	// three peers before finishing.
	float rate_limit = 100000;
	ses1.set_upload_rate_limit(int(rate_limit));
	ses2.set_download_rate_limit(int(rate_limit));
	ses3.set_download_rate_limit(int(rate_limit));
	ses2.set_upload_rate_limit(int(rate_limit / 2));
	ses3.set_upload_rate_limit(int(rate_limit / 2));

	session_settings settings;
	settings.allow_multiple_connections_per_ip = true;
	settings.ignore_limits_on_local_network = false;
	ses1.set_settings(settings);
	ses2.set_settings(settings);
	ses3.set_settings(settings);

#ifndef TORRENT_DISABLE_ENCRYPTION
	pe_settings pes;
	pes.out_enc_policy = pe_settings::forced;
	pes.in_enc_policy = pe_settings::forced;
	ses1.set_pe_settings(pes);
	ses2.set_pe_settings(pes);
	ses3.set_pe_settings(pes);
#endif

	torrent_handle tor1;
	torrent_handle tor2;
	torrent_handle tor3;

	// test using piece sizes smaller than 16kB
	boost::tie(tor1, tor2, tor3) = setup_transfer(&ses1, &ses2, &ses3, true, false, true, "_swarm", 8 * 1024);

	ses1.set_alert_mask(alert::all_categories & ~alert::progress_notification);
	ses2.set_alert_mask(alert::all_categories & ~alert::progress_notification);
	ses3.set_alert_mask(alert::all_categories & ~alert::progress_notification);

	float sum_dl_rate2 = 0.f;
	float sum_dl_rate3 = 0.f;
	int count_dl_rates2 = 0;
	int count_dl_rates3 = 0;

	for (int i = 0; i < 30; ++i)
	{
		print_alerts(ses1, "ses1");
		print_alerts(ses2, "ses2");
		print_alerts(ses3, "ses3");

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();
		torrent_status st3 = tor3.status();

		if (st2.progress < 1.f && st2.progress > 0.5f)
		{
			sum_dl_rate2 += st2.download_payload_rate;
			++count_dl_rates2;
		}
		if (st3.progress < 1.f && st3.progress > 0.5f)
		{
			sum_dl_rate3 += st3.download_rate;
			++count_dl_rates3;
		}

		std::cerr
			<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s "
			<< st1.num_peers << ": "
			<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st2.progress * 100) << "% "
			<< st2.num_peers << " - "
			<< "\033[32m" << int(st3.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[31m" << int(st3.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st3.progress * 100) << "% "
			<< st3.num_peers
			<< std::endl;

		if (tor2.is_seed() && tor3.is_seed()) break;
		test_sleep(1000);
	}

	TEST_CHECK(tor2.is_seed());
	TEST_CHECK(tor3.is_seed());

	float average2 = sum_dl_rate2 / float(count_dl_rates2);
	float average3 = sum_dl_rate3 / float(count_dl_rates3);

	std::cerr << average2 << std::endl;
	std::cerr << "average rate: " << (average2 / 1000.f) << "kB/s - "
		<< (average3 / 1000.f) << "kB/s" << std::endl;

	TEST_CHECK(std::fabs(average2 - float(rate_limit)) < rate_limit / 11.f);
	TEST_CHECK(std::fabs(average3 - float(rate_limit)) < rate_limit / 11.f);
	if (tor2.is_seed() && tor3.is_seed()) std::cerr << "done\n";

	// make sure the files are deleted
	ses1.remove_torrent(tor1, session::delete_files);
	ses2.remove_torrent(tor2, session::delete_files);
	ses3.remove_torrent(tor3, session::delete_files);

	std::auto_ptr<alert> a = ses1.pop_alert();
	ptime end = time_now() + seconds(20);
	while (a.get() == 0 || dynamic_cast<torrent_deleted_alert*>(a.get()) == 0)
	{
		if (ses1.wait_for_alert(end - time_now()) == 0)
		{
			std::cerr << "wait_for_alert() expired" << std::endl;
			break;
		}
		a = ses1.pop_alert();
		assert(a.get());
		std::cerr << a->message() << std::endl;
	}

	TEST_CHECK(dynamic_cast<torrent_deleted_alert*>(a.get()) != 0);

	// there shouldn't be any alerts generated from now on
	// make sure that the timer in wait_for_alert() works
	// this should time out (ret == 0) and it should take
	// about 2 seconds
	ptime start = time_now();
	alert const* ret;
	while (ret = ses1.wait_for_alert(seconds(2)))
	{
		a = ses1.pop_alert();
		std::cerr << ret->message() << std::endl;
		start = time_now();
	}
	TEST_CHECK(time_now() - start < seconds(3));
	TEST_CHECK(time_now() - start >= seconds(2));
}

int test_main()
{
	using namespace libtorrent;
	using namespace boost::filesystem;

	// in case the previous run was terminated
	try { remove_all("./tmp1_swarm"); } catch (std::exception&) {}
	try { remove_all("./tmp2_swarm"); } catch (std::exception&) {}
	try { remove_all("./tmp3_swarm"); } catch (std::exception&) {}

	test_swarm();

	test_sleep(2000);
	TEST_CHECK(!exists("./tmp1_swarm/temporary"));
	TEST_CHECK(!exists("./tmp2_swarm/temporary"));
	TEST_CHECK(!exists("./tmp3_swarm/temporary"));

	remove_all("./tmp1_swarm");
	remove_all("./tmp2_swarm");
	remove_all("./tmp3_swarm");

	return 0;
}

<|endoftext|>