<commit_before>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// <ios>

// template <class charT, class traits> class basic_ios

// char narrow(char_type c, char dfault) const;

#include <ios>
#include <cassert>

int main()
{
    const std::ios ios(0);
    assert(ios.narrow('c', '*') == 'c');
    assert(ios.narrow('\xFE', '*') == '*');
}
<commit_msg>[libcxx] [test] Remove nonportable locale assumption in basic.ios.members/narrow.pass.cpp<commit_after>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// <ios>

// template <class charT, class traits> class basic_ios

// char narrow(char_type c, char dfault) const;

#include <ios>
#include <cassert>

int main()
{
    const std::wios ios(0);
    assert(ios.narrow(L'c', '*') == 'c');
    assert(ios.narrow(L'\u203C', '*') == '*');
}
<|endoftext|>


<commit_before>/*
 * Copyright 2018 Google, Inc.
 *
 * 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 copyright holders 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.
 *
 * Authors: Gabe Black
 */

#ifndef __SYSTEMC_CORE_PROCESS_TYPES_HH__
#define __SYSTEMC_CORE_PROCESS_TYPES_HH__

#include "systemc/core/process.hh"
#include "systemc/core/scheduler.hh"

namespace sc_gem5
{

class Method : public Process
{
  public:
    Method(const char *name, ProcessFuncWrapper *func, bool _dynamic=false) :
        Process(name, func, _dynamic)
    {}

    const char *kind() const override { return "sc_method_process"; }

    sc_core::sc_curr_proc_kind
    procKind() const override
    {
        return sc_core::SC_METHOD_PROC_;
    }
};

class Thread : public Process
{
  public:
    Thread(const char *name, ProcessFuncWrapper *func, bool _dynamic=false) :
        Process(name, func, _dynamic), ctx(nullptr)
    {}

    ~Thread() { delete ctx; }

    const char *kind() const override { return "sc_thread_process"; }

    void throw_it(ExceptionWrapperBase &exc, bool inc_kids) override;

    sc_core::sc_curr_proc_kind
    procKind() const override
    {
        return sc_core::SC_THREAD_PROC_;
    }

    Fiber *
    fiber() override
    {
        if (!ctx)
            ctx = new Context(this, stackSize);
        return ctx;
    }

  private:
    class Context : public Fiber
    {
      public:
        Context(Thread *thread, size_t size) : Fiber(size), thread(thread) {}

      private:
        Thread *thread;

        void
        main() override
        {
            thread->_needsStart = false;
            thread->run();
            thread->terminate();
        }
    };
    friend class Context;

    Context *ctx;
};

class CThread : public Thread
{
  public:
    CThread(const char *name, ProcessFuncWrapper *func, bool _dynamic=false) :
        Thread(name, func, _dynamic)
    {
        // We'll be in the initialization list now, but we shouldn't be.
        popListNode();
    }

    const char *kind() const override { return "sc_cthread_process"; }

    sc_core::sc_curr_proc_kind
    procKind() const override
    {
        return sc_core::SC_CTHREAD_PROC_;
    }
};

} // namespace sc_gem5

#endif  //__SYSTEMC_CORE_PROCESS_TYPES_HH__
<commit_msg>systemc: When a thread completes, yield to the scheduler.<commit_after>/*
 * Copyright 2018 Google, Inc.
 *
 * 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 copyright holders 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.
 *
 * Authors: Gabe Black
 */

#ifndef __SYSTEMC_CORE_PROCESS_TYPES_HH__
#define __SYSTEMC_CORE_PROCESS_TYPES_HH__

#include "systemc/core/process.hh"
#include "systemc/core/scheduler.hh"

namespace sc_gem5
{

class Method : public Process
{
  public:
    Method(const char *name, ProcessFuncWrapper *func, bool _dynamic=false) :
        Process(name, func, _dynamic)
    {}

    const char *kind() const override { return "sc_method_process"; }

    sc_core::sc_curr_proc_kind
    procKind() const override
    {
        return sc_core::SC_METHOD_PROC_;
    }
};

class Thread : public Process
{
  public:
    Thread(const char *name, ProcessFuncWrapper *func, bool _dynamic=false) :
        Process(name, func, _dynamic), ctx(nullptr)
    {}

    ~Thread() { delete ctx; }

    const char *kind() const override { return "sc_thread_process"; }

    void throw_it(ExceptionWrapperBase &exc, bool inc_kids) override;

    sc_core::sc_curr_proc_kind
    procKind() const override
    {
        return sc_core::SC_THREAD_PROC_;
    }

    Fiber *
    fiber() override
    {
        if (!ctx)
            ctx = new Context(this, stackSize);
        return ctx;
    }

  private:
    class Context : public Fiber
    {
      public:
        Context(Thread *thread, size_t size) : Fiber(size), thread(thread) {}

      private:
        Thread *thread;

        void
        main() override
        {
            thread->_needsStart = false;
            thread->run();
            thread->terminate();
            scheduler.yield();
        }
    };
    friend class Context;

    Context *ctx;
};

class CThread : public Thread
{
  public:
    CThread(const char *name, ProcessFuncWrapper *func, bool _dynamic=false) :
        Thread(name, func, _dynamic)
    {
        // We'll be in the initialization list now, but we shouldn't be.
        popListNode();
    }

    const char *kind() const override { return "sc_cthread_process"; }

    sc_core::sc_curr_proc_kind
    procKind() const override
    {
        return sc_core::SC_CTHREAD_PROC_;
    }
};

} // namespace sc_gem5

#endif  //__SYSTEMC_CORE_PROCESS_TYPES_HH__
<|endoftext|>


<commit_before>#line 2 "togo/gfx/renderer/private.ipp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.
*/

#pragma once

#include <togo/config.hpp>
#include <togo/gfx/types.hpp>
#include <togo/gfx/renderer/types.hpp>
#include <togo/gfx/renderer/private.hpp>

namespace togo {
namespace gfx {

namespace renderer {

#define TOGO_GFX_RENDERER_TEARDOWN_RA_(ra, destroy_func)		\
	if (renderer->ra._num > 0) {								\
		for (auto const& slot : renderer->ra._slots) {			\
			if (slot.id._value == ID_VALUE_NULL) {				\
				renderer::destroy_func(renderer, slot.id);		\
			}													\
		}														\
	}

void teardown_base(gfx::Renderer* const renderer) {
	TOGO_GFX_RENDERER_TEARDOWN_RA_(_vertex_buffers, destroy_vertex_buffer);
	TOGO_GFX_RENDERER_TEARDOWN_RA_(_index_buffers, destroy_index_buffer);
	//TOGO_GFX_RENDERER_TEARDOWN_RA_(_textures, destroy_texture);
	//TOGO_GFX_RENDERER_TEARDOWN_RA_(_uniforms, destroy_uniform);
	//TOGO_GFX_RENDERER_TEARDOWN_RA_(_shaders, destroy_shader);
}

} // namespace renderer

} // namespace gfx
} // namespace togo
<commit_msg>gfx/renderer/private: qualified renderer::teardown_base().<commit_after>#line 2 "togo/gfx/renderer/private.ipp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.
*/

#pragma once

#include <togo/config.hpp>
#include <togo/gfx/types.hpp>
#include <togo/gfx/renderer/types.hpp>
#include <togo/gfx/renderer/private.hpp>

namespace togo {
namespace gfx {

#define TOGO_GFX_RENDERER_TEARDOWN_RA_(ra, destroy_func)		\
	if (renderer->ra._num > 0) {								\
		for (auto const& slot : renderer->ra._slots) {			\
			if (slot.id._value == ID_VALUE_NULL) {				\
				renderer::destroy_func(renderer, slot.id);		\
			}													\
		}														\
	}

void renderer::teardown_base(gfx::Renderer* const renderer) {
	TOGO_GFX_RENDERER_TEARDOWN_RA_(_vertex_buffers, destroy_vertex_buffer);
	TOGO_GFX_RENDERER_TEARDOWN_RA_(_index_buffers, destroy_index_buffer);
	//TOGO_GFX_RENDERER_TEARDOWN_RA_(_textures, destroy_texture);
	//TOGO_GFX_RENDERER_TEARDOWN_RA_(_uniforms, destroy_uniform);
	//TOGO_GFX_RENDERER_TEARDOWN_RA_(_shaders, destroy_shader);
}

} // namespace gfx
} // namespace togo
<|endoftext|>


<commit_before>/*=========================================================================

Library:   TubeTK

Copyright 2010 Kitware Inc. 28 Corporate Drive,
Clifton Park, NY, 12065, USA.

All rights reserved.

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

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

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

=========================================================================*/

#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#ifdef __BORLANDC__
#define ITK_LEAN_AND_MEAN
#endif

// It is important to use OrientedImages
#include "itkOrientedImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"

// The following three should be used in every CLI application
#include "tubeMessage.h"
#include "tubeCLIFilterWatcher.h"
#include "tubeCLIProgressReporter.h"
#include "itkTimeProbesCollectorBase.h"

// Includes specific to this CLI application
#include "itkAnisotropicDiffusiveRegistrationFilter.h"
#include "itkVectorCastImageFilter.h"
#include "itkWarpImageFilter.h"
#include "itkLinearInterpolateImageFunction.h"
#include "vtkSmartPointer.h"
#include "vtkPolyDataReader.h"
#include "vtkXMLPolyDataReader.h"

// Must do a forward declaraction of DoIt before including
// tubeCLIHelperFunctions
template< class pixelT, unsigned int dimensionT >
int DoIt( int argc, char * argv[] );

// Must include CLP before including tubeCLIHelperFunctions
#include "tubeAnisotropicDiffusiveDeformableRegistrationCLP.h"

// Includes tube::ParseArgsAndCallDoIt function
#include "tubeCLIHelperFunctions.h"

// Your code should be within the DoIt function...
template< class pixelT, unsigned int dimensionT >
int DoIt( int argc, char * argv[] )
{
  PARSE_ARGS;

  // The timeCollector is used to perform basic profiling of the components
  // of your algorithm.
  itk::TimeProbesCollectorBase timeCollector;

  // CLIProgressReporter is used to communicate progress with the Slicer GUI
  tube::CLIProgressReporter    progressReporter(
      "AnisotropicDiffusiveDeformableRegistration", CLPProcessInformation );
  progressReporter.Start();

  // Typedefs
  const unsigned int                                      ImageDimension = 3;
  typedef pixelT                                          FixedPixelType;
  typedef pixelT                                          MovingPixelType;
  typedef MovingPixelType                                 OutputPixelType;
  typedef double                                          VectorScalarType;
  typedef itk::Image< FixedPixelType, ImageDimension >    FixedImageType;
  typedef itk::Image< MovingPixelType, ImageDimension >   MovingImageType;
  typedef itk::Image< OutputPixelType, ImageDimension >   OutputImageType;
  typedef itk::Vector< VectorScalarType, ImageDimension > VectorType;
  typedef itk::Image< VectorType, ImageDimension >        VectorImageType;
  typedef itk::Image< double, ImageDimension >            WeightImageType;
  typedef itk::Image< VectorType, ImageDimension >        FieldType;

  //--------------------------------------------------------
  typedef itk::AnisotropicDiffusiveRegistrationFilter
      < FixedImageType, MovingImageType, FieldType > RegistrationType;
  typename RegistrationType::Pointer registrator = RegistrationType::New();

  timeCollector.Start( "Loading input data" );
  typedef itk::ImageFileReader< FixedImageType > FixedImageReaderType;
  typename FixedImageReaderType::Pointer fixedImageReader
      = FixedImageReaderType::New();
  fixedImageReader->SetFileName( fixedImageFileName.c_str() );
  try
    {
    fixedImageReader->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Reading volume: Exception caught: "
                        + std::string(err.GetDescription()) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }
  typename FixedImageType::Pointer fixed = fixedImageReader->GetOutput();
  registrator->SetFixedImage( fixed );

  typedef itk::ImageFileReader< MovingImageType > MovingImageReaderType;
  typename MovingImageReaderType::Pointer movingImageReader
      = MovingImageReaderType::New();
  movingImageReader->SetFileName( movingImageFileName.c_str() );
  try
    {
    movingImageReader->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Reading volume: Exception caught: "
                        + std::string(err.GetDescription()) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }
  typename MovingImageType::Pointer moving = movingImageReader->GetOutput();
  registrator->SetMovingImage( moving );

  FieldType::Pointer initField = FieldType::New();
  initField->SetSpacing( fixed->GetSpacing() );
  initField->SetOrigin( fixed->GetOrigin() );
  initField->SetLargestPossibleRegion( fixed->GetLargestPossibleRegion() );
  initField->SetRequestedRegion( fixed->GetRequestedRegion() );
  initField->SetBufferedRegion( fixed->GetBufferedRegion() );
  initField->Allocate();

  // fill initial deformation with zero vectors
  VectorType zeroVec;
  zeroVec.Fill( 0.0 );
  initField->FillBuffer( zeroVec );

  typedef itk::VectorCastImageFilter< FieldType, FieldType > CasterType;
  CasterType::Pointer caster = CasterType::New();
  caster->SetInput( initField );
  caster->InPlaceOff();
  registrator->SetInitialDeformationField( caster->GetOutput() );

  if( organBoundaryFileName != "" )
    {
    // do we have .vtk or .vtp models?
    std::string::size_type loc = organBoundaryFileName.find_last_of(".");
    if( loc == std::string::npos )
      {
      tube::ErrorMessage( "Failed to find an extension for organ boundary" );
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    std::string extension = organBoundaryFileName.substr(loc);
    typename RegistrationType::BorderSurfacePointer borderSurface = NULL;
    if ( extension == std::string(".vtk") )
      {
      vtkSmartPointer< vtkPolyDataReader > polyDataReader
          = vtkPolyDataReader::New();
      polyDataReader->SetFileName( organBoundaryFileName.c_str() );
      polyDataReader->Update();
      borderSurface = polyDataReader->GetOutput();
      }
    else if ( extension == std::string(".vtp") )
      {
      vtkSmartPointer< vtkXMLPolyDataReader > polyDataReader
          = vtkXMLPolyDataReader::New();
      polyDataReader->SetFileName( organBoundaryFileName.c_str() );
      polyDataReader->Update();
      borderSurface = polyDataReader->GetOutput();
      }
    if( !borderSurface )
      {
      tube::ErrorMessage( "Reading polydata: unsuccessful" );
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    registrator->SetBorderSurface( borderSurface );
    }

  if( inputNormalVectorImageFileName != "" )
    {
    typedef itk::ImageFileReader< VectorImageType > VectorImageReaderType;
    typename VectorImageReaderType::Pointer vectorImageReader
        = VectorImageReaderType::New();
    vectorImageReader->SetFileName( inputNormalVectorImageFileName.c_str() );
    try
      {
      vectorImageReader->Update();
      }
    catch( itk::ExceptionObject & err )
      {
      tube::ErrorMessage( "Reading volume: Exception caught: "
                          + std::string(err.GetDescription()) );
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    registrator->SetNormalVectorImage( vectorImageReader->GetOutput() );
    }

  if( inputWeightImageFileName != "" )
    {
    typedef itk::ImageFileReader< WeightImageType > WeightImageReaderType;
    typename WeightImageReaderType::Pointer weightImageReader
        = WeightImageReaderType::New();
    weightImageReader->SetFileName( inputWeightImageFileName.c_str() );
    try
      {
      weightImageReader->Update();
      }
    catch( itk::ExceptionObject & err )
      {
      tube::ErrorMessage( "Reading volume: Exception caught: "
                          + std::string(err.GetDescription()) );
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    registrator->SetWeightImage( weightImageReader->GetOutput() );
    }

  timeCollector.Stop( "Loading input data" );
  double progress = 0.1;
  progressReporter.Report( progress );

  //-------------------------------------------------------------
  timeCollector.Start( "Registration" );
  registrator->SetNumberOfIterations( numberOfIterations );
  registrator->SetComputeRegularizationTerm( !doNotPerformRegularization );
  registrator->SetUseAnisotropicRegularization(
      !doNotUseAnisotropicRegularization );

  registrator->SetTimeStep( timeStep );
  if( lambda > 0.0 )
    {
    tube::ErrorMessage( "Lambda must be negative." );
    timeCollector.Report();
    return EXIT_FAILURE;
    }
  registrator->SetLambda( lambda );

  tube::CLIFilterWatcher watchRegistration(registrator,
                                           "Anisotropic Diffusive Registration",
                                           CLPProcessInformation,
                                           0.8,
                                           progress );

  // warp moving image
  typedef itk::WarpImageFilter< MovingImageType, MovingImageType, FieldType >
      WarperType;
  typename WarperType::Pointer warper = WarperType::New();

  typedef typename WarperType::CoordRepType CoordRepType;
  typedef itk::LinearInterpolateImageFunction<MovingImageType,CoordRepType>
      InterpolatorType;
  typename InterpolatorType::Pointer interpolator = InterpolatorType::New();

  warper->SetInput( moving );
  warper->SetDeformationField( registrator->GetOutput() );
  warper->SetInterpolator( interpolator );
  warper->SetOutputSpacing( fixed->GetSpacing() );
  warper->SetOutputOrigin( fixed->GetOrigin() );
  warper->SetOutputDirection( fixed->GetDirection() );
  warper->SetEdgePaddingValue( 0 );

  // Update triggers the registration
  warper->Update();

  timeCollector.Stop( "Registration" );
  progress = 0.9;
  progressReporter.Report( progress );

  // ---------------------------------------------------------
  timeCollector.Start( "Write outputs" );

  if( outputDeformationFieldFileName != "" )
    {
    typedef itk::ImageFileWriter< FieldType > FieldWriterType;
    typename FieldWriterType::Pointer fieldWriter = FieldWriterType::New();
    fieldWriter->SetFileName( outputDeformationFieldFileName );
    fieldWriter->SetInput( registrator->GetOutput() );
    try
      {
      fieldWriter->Update();
      }
    catch( itk::ExceptionObject & err )
      {
      tube::ErrorMessage( "Writing volume: Exception caught: "
                          + std::string(err.GetDescription()) );
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    }

  if( outputResampledImageFileName != "" )
    {
    typedef itk::ImageFileWriter< MovingImageType > ImageWriterType;
    typename ImageWriterType::Pointer imageWriter = ImageWriterType::New();
    imageWriter->SetFileName( outputResampledImageFileName );
    imageWriter->SetInput( warper->GetOutput() );
    try
      {
      imageWriter->Update();
      }
    catch( itk::ExceptionObject & err )
      {
      tube::ErrorMessage( "Writing volume: Exception caught: "
                          + std::string(err.GetDescription()) );
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    }

  if( outputNormalVectorImageFileName != "" )
    {
    typedef itk::ImageFileWriter< VectorImageType > VectorWriterType;
    typename VectorWriterType::Pointer vectorWriter = VectorWriterType::New();
    vectorWriter->SetFileName( outputNormalVectorImageFileName );
    vectorWriter->SetInput( registrator->GetNormalVectorImage() );
    try
      {
      vectorWriter->Update();
      }
    catch( itk::ExceptionObject & err )
      {
      tube::ErrorMessage( "Writing volume: Exception caught: "
                          + std::string(err.GetDescription()) );
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    }

  if( outputWeightImageFileName != "" )
    {
    typedef itk::ImageFileWriter< WeightImageType > WeightWriterType;
    typename WeightWriterType::Pointer weightWriter = WeightWriterType::New();
    weightWriter->SetFileName( outputWeightImageFileName );
    weightWriter->SetInput( registrator->GetWeightImage() );
    try
      {
      weightWriter->Update();
      }
    catch( itk::ExceptionObject & err )
      {
      tube::ErrorMessage( "Writing volume: Exception caught: "
                          + std::string(err.GetDescription()) );
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    }

  timeCollector.Stop( "Write outputs" );
  progress = 1.0;
  progressReporter.Report( progress );

  progressReporter.End( );
  timeCollector.Report();
  return EXIT_SUCCESS;
}

// Main
int main( int argc, char **argv )
{
  PARSE_ARGS;

  // You may need to update this line if, in the project's .xml CLI file,
  //   you change the variable name for the inputVolume.
  return tube::ParseArgsAndCallDoIt( fixedImageFileName, argc, argv );
}
<commit_msg>STYLE: Remove redundant typedef<commit_after>/*=========================================================================

Library:   TubeTK

Copyright 2010 Kitware Inc. 28 Corporate Drive,
Clifton Park, NY, 12065, USA.

All rights reserved.

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

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

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

=========================================================================*/

#if defined(_MSC_VER)
#pragma warning ( disable : 4786 )
#endif

#ifdef __BORLANDC__
#define ITK_LEAN_AND_MEAN
#endif

// It is important to use OrientedImages
#include "itkOrientedImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"

// The following three should be used in every CLI application
#include "tubeMessage.h"
#include "tubeCLIFilterWatcher.h"
#include "tubeCLIProgressReporter.h"
#include "itkTimeProbesCollectorBase.h"

// Includes specific to this CLI application
#include "itkAnisotropicDiffusiveRegistrationFilter.h"
#include "itkVectorCastImageFilter.h"
#include "itkWarpImageFilter.h"
#include "itkLinearInterpolateImageFunction.h"
#include "vtkSmartPointer.h"
#include "vtkPolyDataReader.h"
#include "vtkXMLPolyDataReader.h"

// Must do a forward declaraction of DoIt before including
// tubeCLIHelperFunctions
template< class pixelT, unsigned int dimensionT >
int DoIt( int argc, char * argv[] );

// Must include CLP before including tubeCLIHelperFunctions
#include "tubeAnisotropicDiffusiveDeformableRegistrationCLP.h"

// Includes tube::ParseArgsAndCallDoIt function
#include "tubeCLIHelperFunctions.h"

// Your code should be within the DoIt function...
template< class pixelT, unsigned int dimensionT >
int DoIt( int argc, char * argv[] )
{
  PARSE_ARGS;

  // The timeCollector is used to perform basic profiling of the components
  // of your algorithm.
  itk::TimeProbesCollectorBase timeCollector;

  // CLIProgressReporter is used to communicate progress with the Slicer GUI
  tube::CLIProgressReporter    progressReporter(
      "AnisotropicDiffusiveDeformableRegistration", CLPProcessInformation );
  progressReporter.Start();

  // Typedefs
  const unsigned int                                      ImageDimension = 3;
  typedef pixelT                                          FixedPixelType;
  typedef pixelT                                          MovingPixelType;
  typedef MovingPixelType                                 OutputPixelType;
  typedef double                                          VectorScalarType;
  typedef itk::Image< FixedPixelType, ImageDimension >    FixedImageType;
  typedef itk::Image< MovingPixelType, ImageDimension >   MovingImageType;
  typedef itk::Image< OutputPixelType, ImageDimension >   OutputImageType;
  typedef itk::Vector< VectorScalarType, ImageDimension > VectorType;
  typedef itk::Image< VectorType, ImageDimension >        VectorImageType;
  typedef itk::Image< double, ImageDimension >            WeightImageType;

  //--------------------------------------------------------
  typedef itk::AnisotropicDiffusiveRegistrationFilter
      < FixedImageType, MovingImageType, VectorImageType > RegistrationType;
  typename RegistrationType::Pointer registrator = RegistrationType::New();

  timeCollector.Start( "Loading input data" );
  typedef itk::ImageFileReader< FixedImageType > FixedImageReaderType;
  typename FixedImageReaderType::Pointer fixedImageReader
      = FixedImageReaderType::New();
  fixedImageReader->SetFileName( fixedImageFileName.c_str() );
  try
    {
    fixedImageReader->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Reading volume: Exception caught: "
                        + std::string(err.GetDescription()) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }
  typename FixedImageType::Pointer fixed = fixedImageReader->GetOutput();
  registrator->SetFixedImage( fixed );

  typedef itk::ImageFileReader< MovingImageType > MovingImageReaderType;
  typename MovingImageReaderType::Pointer movingImageReader
      = MovingImageReaderType::New();
  movingImageReader->SetFileName( movingImageFileName.c_str() );
  try
    {
    movingImageReader->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Reading volume: Exception caught: "
                        + std::string(err.GetDescription()) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }
  typename MovingImageType::Pointer moving = movingImageReader->GetOutput();
  registrator->SetMovingImage( moving );

  VectorImageType::Pointer initField = VectorImageType::New();
  initField->SetSpacing( fixed->GetSpacing() );
  initField->SetOrigin( fixed->GetOrigin() );
  initField->SetLargestPossibleRegion( fixed->GetLargestPossibleRegion() );
  initField->SetRequestedRegion( fixed->GetRequestedRegion() );
  initField->SetBufferedRegion( fixed->GetBufferedRegion() );
  initField->Allocate();

  // fill initial deformation with zero vectors
  VectorType zeroVec;
  zeroVec.Fill( 0.0 );
  initField->FillBuffer( zeroVec );

  typedef itk::VectorCastImageFilter< VectorImageType, VectorImageType >
      CasterType;
  CasterType::Pointer caster = CasterType::New();
  caster->SetInput( initField );
  caster->InPlaceOff();
  registrator->SetInitialDeformationField( caster->GetOutput() );

  if( organBoundaryFileName != "" )
    {
    // do we have .vtk or .vtp models?
    std::string::size_type loc = organBoundaryFileName.find_last_of(".");
    if( loc == std::string::npos )
      {
      tube::ErrorMessage( "Failed to find an extension for organ boundary" );
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    std::string extension = organBoundaryFileName.substr(loc);
    typename RegistrationType::BorderSurfacePointer borderSurface = NULL;
    if ( extension == std::string(".vtk") )
      {
      vtkSmartPointer< vtkPolyDataReader > polyDataReader
          = vtkPolyDataReader::New();
      polyDataReader->SetFileName( organBoundaryFileName.c_str() );
      polyDataReader->Update();
      borderSurface = polyDataReader->GetOutput();
      }
    else if ( extension == std::string(".vtp") )
      {
      vtkSmartPointer< vtkXMLPolyDataReader > polyDataReader
          = vtkXMLPolyDataReader::New();
      polyDataReader->SetFileName( organBoundaryFileName.c_str() );
      polyDataReader->Update();
      borderSurface = polyDataReader->GetOutput();
      }
    if( !borderSurface )
      {
      tube::ErrorMessage( "Reading polydata: unsuccessful" );
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    registrator->SetBorderSurface( borderSurface );
    }

  if( inputNormalVectorImageFileName != "" )
    {
    typedef itk::ImageFileReader< VectorImageType > VectorImageReaderType;
    typename VectorImageReaderType::Pointer vectorImageReader
        = VectorImageReaderType::New();
    vectorImageReader->SetFileName( inputNormalVectorImageFileName.c_str() );
    try
      {
      vectorImageReader->Update();
      }
    catch( itk::ExceptionObject & err )
      {
      tube::ErrorMessage( "Reading volume: Exception caught: "
                          + std::string(err.GetDescription()) );
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    registrator->SetNormalVectorImage( vectorImageReader->GetOutput() );
    }

  if( inputWeightImageFileName != "" )
    {
    typedef itk::ImageFileReader< WeightImageType > WeightImageReaderType;
    typename WeightImageReaderType::Pointer weightImageReader
        = WeightImageReaderType::New();
    weightImageReader->SetFileName( inputWeightImageFileName.c_str() );
    try
      {
      weightImageReader->Update();
      }
    catch( itk::ExceptionObject & err )
      {
      tube::ErrorMessage( "Reading volume: Exception caught: "
                          + std::string(err.GetDescription()) );
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    registrator->SetWeightImage( weightImageReader->GetOutput() );
    }

  timeCollector.Stop( "Loading input data" );
  double progress = 0.1;
  progressReporter.Report( progress );

  //-------------------------------------------------------------
  timeCollector.Start( "Registration" );
  registrator->SetNumberOfIterations( numberOfIterations );
  registrator->SetComputeRegularizationTerm( !doNotPerformRegularization );
  registrator->SetUseAnisotropicRegularization(
      !doNotUseAnisotropicRegularization );

  registrator->SetTimeStep( timeStep );
  if( lambda > 0.0 )
    {
    tube::ErrorMessage( "Lambda must be negative." );
    timeCollector.Report();
    return EXIT_FAILURE;
    }
  registrator->SetLambda( lambda );

  tube::CLIFilterWatcher watchRegistration(registrator,
                                           "Anisotropic Diffusive Registration",
                                           CLPProcessInformation,
                                           0.8,
                                           progress );

  // warp moving image
  typedef
      itk::WarpImageFilter< MovingImageType, MovingImageType, VectorImageType >
      WarperType;
  typename WarperType::Pointer warper = WarperType::New();

  typedef typename WarperType::CoordRepType CoordRepType;
  typedef itk::LinearInterpolateImageFunction<MovingImageType,CoordRepType>
      InterpolatorType;
  typename InterpolatorType::Pointer interpolator = InterpolatorType::New();

  warper->SetInput( moving );
  warper->SetDeformationField( registrator->GetOutput() );
  warper->SetInterpolator( interpolator );
  warper->SetOutputSpacing( fixed->GetSpacing() );
  warper->SetOutputOrigin( fixed->GetOrigin() );
  warper->SetOutputDirection( fixed->GetDirection() );
  warper->SetEdgePaddingValue( 0 );

  // Update triggers the registration
  warper->Update();

  timeCollector.Stop( "Registration" );
  progress = 0.9;
  progressReporter.Report( progress );

  // ---------------------------------------------------------
  timeCollector.Start( "Write outputs" );

  if( outputDeformationFieldFileName != "" )
    {
    typedef itk::ImageFileWriter< VectorImageType > FieldWriterType;
    typename FieldWriterType::Pointer fieldWriter = FieldWriterType::New();
    fieldWriter->SetFileName( outputDeformationFieldFileName );
    fieldWriter->SetInput( registrator->GetOutput() );
    try
      {
      fieldWriter->Update();
      }
    catch( itk::ExceptionObject & err )
      {
      tube::ErrorMessage( "Writing volume: Exception caught: "
                          + std::string(err.GetDescription()) );
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    }

  if( outputResampledImageFileName != "" )
    {
    typedef itk::ImageFileWriter< MovingImageType > ImageWriterType;
    typename ImageWriterType::Pointer imageWriter = ImageWriterType::New();
    imageWriter->SetFileName( outputResampledImageFileName );
    imageWriter->SetInput( warper->GetOutput() );
    try
      {
      imageWriter->Update();
      }
    catch( itk::ExceptionObject & err )
      {
      tube::ErrorMessage( "Writing volume: Exception caught: "
                          + std::string(err.GetDescription()) );
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    }

  if( outputNormalVectorImageFileName != "" )
    {
    typedef itk::ImageFileWriter< VectorImageType > VectorWriterType;
    typename VectorWriterType::Pointer vectorWriter = VectorWriterType::New();
    vectorWriter->SetFileName( outputNormalVectorImageFileName );
    vectorWriter->SetInput( registrator->GetNormalVectorImage() );
    try
      {
      vectorWriter->Update();
      }
    catch( itk::ExceptionObject & err )
      {
      tube::ErrorMessage( "Writing volume: Exception caught: "
                          + std::string(err.GetDescription()) );
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    }

  if( outputWeightImageFileName != "" )
    {
    typedef itk::ImageFileWriter< WeightImageType > WeightWriterType;
    typename WeightWriterType::Pointer weightWriter = WeightWriterType::New();
    weightWriter->SetFileName( outputWeightImageFileName );
    weightWriter->SetInput( registrator->GetWeightImage() );
    try
      {
      weightWriter->Update();
      }
    catch( itk::ExceptionObject & err )
      {
      tube::ErrorMessage( "Writing volume: Exception caught: "
                          + std::string(err.GetDescription()) );
      timeCollector.Report();
      return EXIT_FAILURE;
      }
    }

  timeCollector.Stop( "Write outputs" );
  progress = 1.0;
  progressReporter.Report( progress );

  progressReporter.End( );
  timeCollector.Report();
  return EXIT_SUCCESS;
}

// Main
int main( int argc, char **argv )
{
  PARSE_ARGS;

  // You may need to update this line if, in the project's .xml CLI file,
  //   you change the variable name for the inputVolume.
  return tube::ParseArgsAndCallDoIt( fixedImageFileName, argc, argv );
}
<|endoftext|>


<commit_before>#include "training/graph_group_sync.h"

namespace marian {

SyncGraphGroup::SyncGraphGroup(Ptr<Config> config)
    : GraphGroup(config),
      ExponentialSmoothing{options_->get<float>("exponential-smoothing")},
      delay_{options_->get<size_t>("optimizer-delay")} { // @TODO: rename to something else; delay means delayed updated, not accumulation

  mpi_ = initMPI(/*multiThreaded=*/false); // when not running under MPI, this will be a fake object that represents a one-MPI-process setup

  devices_ = options_->getDevices(mpi_->myMPIRank(), mpi_->numMPIProcesses());
  for(auto device : devices_) {
    auto graph = New<ExpressionGraph>();
    graph->setDevice(device);
    graph->reserveWorkspaceMB(options_->get<size_t>("workspace"));
    graph->getBackend()->setClip(options_->get<float>("clip-gemm"));

    graphs_.push_back(graph);
    shardOpt_.push_back(Optimizer(options_));
    builders_.push_back(models::from_config(options_, models::usage::training));
  }

  // Note: We may well end up with only one MPI process or only one graph per worker.
  // This part of the code will not special-case any of this here.
  // Rather, it is assumed that the communicator knows to reduce unnecessary transfers to no-ops.
  comm_ = createCommunicator(graphs_, /*noNccl=*/options_->get<bool>("no-nccl", false), /*mpi=*/mpi_);
}

void SyncGraphGroup::setScheduler(Ptr<Scheduler> scheduler) /*override*/ {
  scheduler_ = scheduler;
  // optimizer has to be registered last to see changes of learning rate
  // @TODO: ^^Fix this comment. Either it refers to the scheduler, or it should be moved. Which one?
  scheduler_->registerTrainingObserver(scheduler_);

  for(auto opt : shardOpt_)
    scheduler_->registerTrainingObserver(opt);
}

void SyncGraphGroup::initialize(const Ptr<data::Batch>& exampleBatch) {
  // Initialize 0th graph with random weights in one forward step
  THREAD_GUARD({
    builders_[0]->build(graphs_[0], exampleBatch);
    graphs_[0]->forward();
  });

  // Copy weights from 0th graph to all other graphs
  // to have equal weights across devices
  ThreadPool pool(graphs_.size() - 1, graphs_.size() - 1);
  for(size_t i = 1; i < graphs_.size(); ++i) {
    auto init = [&](size_t i) {
      // initialize t-th graph and weights
      builders_[i]->build(graphs_[i], exampleBatch);
      graphs_[i]->forward();
      // overwrite weights of t-th graph with weights from 0th graph
      graphs_[i]->params()->vals()->copyFrom(graphs_[0]->params()->vals());
    };
    pool.enqueue(init, i);
  }
  // ThreadPool destructor waits until completion of all tasks.
}

void SyncGraphGroup::initializeAvg() {
  Ptr<ExpressionGraph> graphAvg; // CPU-side temp
  std::string name = options_->get<std::string>("model");
  if(filesystem::exists(name + ".orig.npz")) {
    // Load the averaged parameters into a temporary graph
    graphAvg = New<ExpressionGraph>();
    graphAvg->setDevice({0, DeviceType::cpu});
    graphAvg->load(name, false);
    graphAvg->forward(); // initialize parameters if needed
  }

  auto init = [&](size_t localDeviceIndex, size_t begin, size_t end) {
    size_t size = end-begin;

    // get the device-specific allocator
    auto paramsAllocator = New<TensorAllocator>(graphs_[localDeviceIndex]->getBackend());
    paramsAllocs_[localDeviceIndex] = paramsAllocator;

    paramsAllocator->reserveExact(size * sizeof(float));

    Tensor paramAvg;
    paramsAllocator->allocate(paramAvg, {1, (int)size});
    paramsAvg_[localDeviceIndex] = paramAvg;

    if(graphAvg)
      paramAvg->copyFrom(graphAvg  ->params()->vals()->subtensor(begin, size));
    else
      paramAvg->copyFrom(graphs_[0]->params()->vals()->subtensor(begin, size));

    // note: for multi-node, graphAvg and graphs_[0] contain a complete copy, from which
    // each MPI process copies only part into its respective shard(s)
  };

  paramsAllocs_.resize(graphs_.size()); // allocators
  paramsAvg_.resize(graphs_.size());    // averaged parameters (shards; distributed over MPI processes if applicable)
  comm_->foreach(init, /*parallel=*/false); // @TODO: is sequential operation necessary here? (is the allocation stuff sufficiently reentrant or thread-separated?)
}

Ptr<data::BatchStats> SyncGraphGroup::collectStats() {
    size_t multiplier = devices_.size() * mpi_->numMPIProcesses() * delay_;
    return GraphGroup::collectStats(graphs_[0], builders_[0], multiplier);
}

void SyncGraphGroup::update(Ptr<data::Batch> batch) /*override*/ {
  ABORT_IF(finalized_, "Training has already finished.");

  // distribute the batch over (delay, local device, MPI rank)
  size_t numSubBatches = delay_ * devices_.size() * mpi_->numMPIProcesses();
  auto subBatches = batch->split(numSubBatches);
  subBatches.resize(numSubBatches); // pad with nullptrs if out of data

  // Helper to access the subBatches array
  auto getSubBatch = [&](size_t t, size_t localDeviceIndex, size_t rank) {
    // 't' (the delay) should be slowest changing dimension. If subBatches are sorted by
    // length, then grouping sentences of similar length into the same delay step can
    // reduce unnecessary time spent in padding.
    return subBatches[(t * mpi_->numMPIProcesses() + rank) * devices_.size() + localDeviceIndex];
  };

  // Upon very first execution, reset everything
  if(first_) {
    LOG(info, "[{}] Processing first minibatch. Batches are processed as {} processes x {} GPUs/process x {} delay steps.",
         mpi_->idStr(), mpi_->numMPIProcesses(), devices_.size(), delay_);
    initialize(subBatches.front());
    if(mvAvg_ && paramsAvg_.empty())
      initializeAvg();
    first_ = false;
  }

  // Compute gradients
  // This happens in multiple steps in case of delay_ > 1.
  std::vector<float> localDeviceCosts(devices_.size(), 0.f); // [local device index] aggregate cost for each local device
  for (size_t t = 0; t < delay_; t++) {
    // Execute single forward/backward step
    auto forwardBackward = [&](size_t localDeviceIndex, size_t /*begin*/, size_t /*end*/) {
      auto graph = graphs_[localDeviceIndex];
      auto subBatch = getSubBatch(t, localDeviceIndex, mpi_->myMPIRank());

      // temporary for the cost
      // @BUGBUG: must exist before first allocations; must do stuff in initialize()
      //auto costTmp = graph->param("special:costTmp", {}, inits::zeros);
      //if (t == 0)
      //    costTmp->grad()->set(0.0f);

      if(subBatch) {
        timer::Timer timer;
        auto costNode = builders_[localDeviceIndex]->build(graph, subBatch);
        timer.format(2, "after build: %ws");
        graph->forward();
        timer.format(2, "after forward (no sync): %ws");
        //localDeviceCosts[localDeviceIndex] += costNode->scalar();
        graph->backward(/*zero=*/t == 0); // only reset gradients to 0 if t = 0
        timer.format(2, "after backward (no sync): %ws");
        localDeviceCosts[localDeviceIndex] += costNode->scalar(); // moved here for time measurements; @TODO: move this back
        timer.format(2, "after scalar() (that's a sync): %ws");
        //// record cost in a gradient
        //using namespace functional;
        //Element(_1 += _2, costTmp->grad(), costNode->val()); // stick it into a fake gradient that gets aggregated
        //// @TODO: Complete this. We still need to move it back from grad to val, which is tricky due to sharding.
      }
      else { // empty batch: execute do-nothing fw-bw step for proper inits and resets
        graph->forward();
        graph->backward(/*zero=*/t == 0);
      }
    };

    comm_->foreach(forwardBackward); // compute gradients in parallel on each device. Aggregate if delay_ > 1.
  }
  // At this point, each device on eacn MPI process has a gradient aggregated over a subset of the sub-batches.

  // Update parameter shard with gradient shard
  auto update = [&](size_t idx, size_t begin, size_t end) {
    auto curGrad = graphs_[idx]->params()->grads()->subtensor(begin, end-begin);
    auto curParam = graphs_[idx]->params()->vals()->subtensor(begin, end-begin);

    // if individual gradients were averages, then need to average again over all subBatches
    auto div = subBatches.size();
    if (options_->get<std::string>("cost-type") == "ce-sum")
      div = 1;
    if(div != 1) {
      using namespace functional;
      Element(_1 = _1 / (float)div, curGrad);
    }

    // actual model update
    shardOpt_[idx]->update(curParam, curGrad);

    if(mvAvg_)
      updateAvgParams(
          paramsAvg_[idx], curParam, scheduler_->numberOfBatches());

    // fetch the aggregated cost
    // @TODO: We are sharded here. Need to copy costTmp->grad() to costTmp->val().
    //auto costTmp = graphs_[idx]->param("special:costTmp", {}, inits::zeros);
    //costTmp->val()->copyFrom(costTmp->grad());
  };

  timer::Timer timer;
  comm_->scatterReduce(); // reduce gradients across all devices (globally) into shards
  timer.format(2, "after scatterReduce (has sync): %ws");
  comm_->foreach(update); // per-shard model-update
  timer.format(2, "after model update (no sync): %ws");
  comm_->allGather();     // distribute param value shards back
  timer.format(2, "after allGather (has sync): %ws");

  // cost across all local devices
  // @TODO: We should report cost aggregated over all MPI processes.
  float cost = 0;
  for(auto& c : localDeviceCosts) // localDeviceCosts is already summed up over delay steps
    cost += c;

  // if cost is average-based, we need to turn the sum over devices into an average as well
  if(options_->get<std::string>("cost-type") != "ce-sum")
    cost /= numSubBatches;

  // the cost is not aggregated across MPI workers here; that is done inside the scheduler

  if(scheduler_) {
    // track and log cost
    scheduler_->update(cost, subBatches, mpi_);

    // save intermediate model (and optimizer state) to file
    if(scheduler_->saving()) {
      save();
    }

    // process valid data set
    // This may save a model as well.
    if(scheduler_->validating()) {
      swapParamsAvg();
      if (isMainProcess())
        scheduler_->validate(graphs_);
      swapParamsAvg();
    }
  }
}

void SyncGraphGroup::load() /*override*/ {
  if(!options_->get<bool>("no-reload")) {
    std::string name = options_->get<std::string>("model");

    if(filesystem::exists(name)) {
      if(scheduler_)
        scheduler_->load(name);

      std::string nameGraph = name;
      if(mvAvg_ && filesystem::exists(name + ".orig.npz"))
        // Load the original parameters from model.npz.orig.npz
        nameGraph += ".orig.npz";

      size_t i = 0;
      for(auto graph : graphs_)
        builders_[i++]->load(graph, nameGraph); // we just load it N times from disk (it'll be in disk cache after the first)

      // @TODO: probably we want to have the list of DeviceIds as an attribute
      std::vector<Ptr<Backend>> backends;
      for(auto graph : graphs_)
        backends.push_back(graph->getBackend());
      shardOpt_[0]->load(name + ".optimizer.npz", shardOpt_, backends,
        [&](const std::vector<float>& data, const OptimizerBase::ScatterStateSetFunc& setFn) {
          comm_->scatterState(data, setFn);
        });
    } else if(options_->has("pretrained-model")) {
      std::string nameInit = options_->get<std::string>("pretrained-model");
      LOG(info,
          "Initialize model weights with the pre-trained model {}",
          nameInit);

      size_t i = 0;
      for(auto graph : graphs_)
        builders_[i++]->load(graph, nameInit, false);
    }
  }
}

void SyncGraphGroup::save(bool final) /*override*/ {
  barrier(); // (for better grouping of log messages)
  LOG(info, "[{}] save() line {}!", this->mpi_->idStr(), __LINE__);
  // do final validation
  if(final && scheduler_) {
    // bring the smoothed model in
    // Note that it is sharded. For multi-node, it is sharded over multiple machines, so this is a network access.
    // Also note that the swap must run on all MPI processes concurrently, although only one actually validates.
    LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
    swapParamsAvg();
    LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
    if (isMainProcess()) // in multi-node, only first MPI process saves the model (they are all identical)
      scheduler_->validate(graphs_, true);
    LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
    swapParamsAvg();
    LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
  }

  std::string name = options_->get<std::string>("model");

  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
  barrier(); // (for better grouping of log messages)
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
  // if smoothing then save original (unsmoothed) parameters as well
  // @TODO: Check whether we are reloading the correct file (the unsmoothed one).
  if(mvAvg_ && paramsAvg_.size() > 0 && isMainProcess()) // only save from one MPI process
    // Save the original parameters in model.npz.orig.npz
    builders_[0]->save(graphs_[0], name + ".orig.npz", true);

  // Temporarily switch to the averaged parameters
  // Note: the smoothed model is sharded across GPUs, and across MPI processes if applicable. This brings it into MPI process[*].device[*]
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
  swapParamsAvg();
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);

  // save main model file
  if (isMainProcess()) { // only save from one MPI process
    // if not overwrite then save a copy with number of updates in the model pathname
    LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
    if(!options_->get<bool>("overwrite") && !final) {
      std::string numberOfBatches
          = scheduler_ ? std::to_string(scheduler_->numberOfBatches())
                       : "unknown";
      std::string nameOverwrite = name;
      nameOverwrite.replace(name.size() - 4, 4, ".iter" + numberOfBatches + ".npz"); // @TODO: use insert?
      builders_[0]->save(graphs_[0], nameOverwrite);
    }
    LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
    // save main model file
    builders_[0]->save(graphs_[0], name, true);
    LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
    // save scheduler-related state
    if (scheduler_)
      scheduler_->save(name);
    LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
  }

  // Switch back to the original parameters
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
  swapParamsAvg();
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);

#if 1 // temporary, for testing of saving distributed models; must be identical to .orig.npz
  if(mvAvg_ && paramsAvg_.size() > 0 && isMainProcess())
    builders_[0]->save(graphs_[0], name + ".orig_after_swapping.npz", true);
#endif
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
  barrier(); // (for better grouping of log messages)
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);

  // persist optimizer state
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
  shardOpt_[0]->save(name + ".optimizer.npz", shardOpt_,
    [&](const OptimizerBase::GatherStateGetFunc& getFn) {
      return comm_->gatherState(getFn);
    },
    isMainProcess());
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);

  barrier(); // (for better grouping of log messages)
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
}

}  // namespace marian
<commit_msg>fixed the time measurement (again); cleaned up comments<commit_after>#include "training/graph_group_sync.h"

namespace marian {

SyncGraphGroup::SyncGraphGroup(Ptr<Config> config)
    : GraphGroup(config),
      ExponentialSmoothing{options_->get<float>("exponential-smoothing")},
      delay_{options_->get<size_t>("optimizer-delay")} { // @TODO: rename to something else; delay means delayed updated, not accumulation

  mpi_ = initMPI(/*multiThreaded=*/false); // when not running under MPI, this will be a fake object that represents a one-MPI-process setup

  devices_ = options_->getDevices(mpi_->myMPIRank(), mpi_->numMPIProcesses());
  for(auto device : devices_) {
    auto graph = New<ExpressionGraph>();
    graph->setDevice(device);
    graph->reserveWorkspaceMB(options_->get<size_t>("workspace"));
    graph->getBackend()->setClip(options_->get<float>("clip-gemm"));

    graphs_.push_back(graph);
    shardOpt_.push_back(Optimizer(options_));
    builders_.push_back(models::from_config(options_, models::usage::training));
  }

  // Note: We may well end up with only one MPI process or only one graph per worker.
  // This part of the code will not special-case any of this here.
  // Rather, it is assumed that the communicator knows to reduce unnecessary transfers to no-ops.
  comm_ = createCommunicator(graphs_, /*noNccl=*/options_->get<bool>("no-nccl", false), /*mpi=*/mpi_);
}

void SyncGraphGroup::setScheduler(Ptr<Scheduler> scheduler) /*override*/ {
  scheduler_ = scheduler;
  // optimizer has to be registered last to see changes of learning rate
  // @TODO: ^^Fix this comment. Either it refers to the scheduler, or it should be moved. Which one?
  scheduler_->registerTrainingObserver(scheduler_);

  for(auto opt : shardOpt_)
    scheduler_->registerTrainingObserver(opt);
}

void SyncGraphGroup::initialize(const Ptr<data::Batch>& exampleBatch) {
  // Initialize 0th graph with random weights in one forward step
  THREAD_GUARD({
    builders_[0]->build(graphs_[0], exampleBatch);
    graphs_[0]->forward();
  });

  // Copy weights from 0th graph to all other graphs
  // to have equal weights across devices
  ThreadPool pool(graphs_.size() - 1, graphs_.size() - 1);
  for(size_t i = 1; i < graphs_.size(); ++i) {
    auto init = [&](size_t i) {
      // initialize t-th graph and weights
      builders_[i]->build(graphs_[i], exampleBatch);
      graphs_[i]->forward();
      // overwrite weights of t-th graph with weights from 0th graph
      graphs_[i]->params()->vals()->copyFrom(graphs_[0]->params()->vals());
    };
    pool.enqueue(init, i);
  }
  // ThreadPool destructor waits until completion of all tasks.
}

void SyncGraphGroup::initializeAvg() {
  Ptr<ExpressionGraph> graphAvg; // CPU-side temp
  std::string name = options_->get<std::string>("model");
  if(filesystem::exists(name + ".orig.npz")) {
    // Load the averaged parameters into a temporary graph
    graphAvg = New<ExpressionGraph>();
    graphAvg->setDevice({0, DeviceType::cpu});
    graphAvg->load(name, false);
    graphAvg->forward(); // initialize parameters if needed
  }

  auto init = [&](size_t localDeviceIndex, size_t begin, size_t end) {
    size_t size = end-begin;

    // get the device-specific allocator
    auto paramsAllocator = New<TensorAllocator>(graphs_[localDeviceIndex]->getBackend());
    paramsAllocs_[localDeviceIndex] = paramsAllocator;

    paramsAllocator->reserveExact(size * sizeof(float));

    Tensor paramAvg;
    paramsAllocator->allocate(paramAvg, {1, (int)size});
    paramsAvg_[localDeviceIndex] = paramAvg;

    if(graphAvg)
      paramAvg->copyFrom(graphAvg  ->params()->vals()->subtensor(begin, size));
    else
      paramAvg->copyFrom(graphs_[0]->params()->vals()->subtensor(begin, size));

    // note: for multi-node, graphAvg and graphs_[0] contain a complete copy, from which
    // each MPI process copies only part into its respective shard(s)
  };

  paramsAllocs_.resize(graphs_.size()); // allocators
  paramsAvg_.resize(graphs_.size());    // averaged parameters (shards; distributed over MPI processes if applicable)
  comm_->foreach(init, /*parallel=*/false); // @TODO: is sequential operation necessary here? (is the allocation stuff sufficiently reentrant or thread-separated?)
}

Ptr<data::BatchStats> SyncGraphGroup::collectStats() {
    size_t multiplier = devices_.size() * mpi_->numMPIProcesses() * delay_;
    return GraphGroup::collectStats(graphs_[0], builders_[0], multiplier);
}

void SyncGraphGroup::update(Ptr<data::Batch> batch) /*override*/ {
  ABORT_IF(finalized_, "Training has already finished.");

  // distribute the batch over (delay, local device, MPI rank)
  size_t numSubBatches = delay_ * devices_.size() * mpi_->numMPIProcesses();
  auto subBatches = batch->split(numSubBatches);
  subBatches.resize(numSubBatches); // pad with nullptrs if out of data

  // Helper to access the subBatches array
  auto getSubBatch = [&](size_t t, size_t localDeviceIndex, size_t rank) {
    // 't' (the delay) should be slowest changing dimension. If subBatches are sorted by
    // length, then grouping sentences of similar length into the same delay step can
    // reduce unnecessary time spent in padding.
    return subBatches[(t * mpi_->numMPIProcesses() + rank) * devices_.size() + localDeviceIndex];
  };

  // Upon very first execution, reset everything
  if(first_) {
    LOG(info, "[{}] Processing first minibatch. Batches are processed as {} processes x {} GPUs/process x {} delay steps.",
         mpi_->idStr(), mpi_->numMPIProcesses(), devices_.size(), delay_);
    initialize(subBatches.front());
    if(mvAvg_ && paramsAvg_.empty())
      initializeAvg();
    first_ = false;
  }

  // Compute gradients
  // This happens in multiple steps in case of delay_ > 1.
  std::vector<float> localDeviceCosts(devices_.size(), 0.f); // [local device index] aggregate cost for each local device
  for (size_t t = 0; t < delay_; t++) {
    // Execute single forward/backward step
    auto forwardBackward = [&](size_t localDeviceIndex, size_t /*begin*/, size_t /*end*/) {
      auto graph = graphs_[localDeviceIndex];
      auto subBatch = getSubBatch(t, localDeviceIndex, mpi_->myMPIRank());

      if(subBatch) {
        timer::Timer timer;
        auto costNode = builders_[localDeviceIndex]->build(graph, subBatch);
        LOG(info, timer.format(2, "after build: %ws"));
        graph->forward();
        LOG(info, timer.format(2, "after forward (no sync): %ws"));
        //localDeviceCosts[localDeviceIndex] += costNode->scalar();
        graph->backward(/*zero=*/t == 0); // only reset gradients to 0 if t = 0
        LOG(info, timer.format(2, "after backward (no sync): %ws"));
        localDeviceCosts[localDeviceIndex] += costNode->scalar(); // moved here for time measurements; @TODO: move this back
        LOG(info, timer.format(2, "after scalar() (that's a sync): %ws"));
      }
      else { // empty batch: execute do-nothing fw-bw step for proper inits and resets
        graph->forward();
        graph->backward(/*zero=*/t == 0);
      }
    };

    comm_->foreach(forwardBackward); // compute gradients in parallel on each device. Aggregate if delay_ > 1.
  }
  // At this point, each device on eacn MPI process has a gradient aggregated over a subset of the sub-batches.

  // Update parameter shard with gradient shard
  auto update = [&](size_t idx, size_t begin, size_t end) {
    auto curGrad = graphs_[idx]->params()->grads()->subtensor(begin, end-begin);
    auto curParam = graphs_[idx]->params()->vals()->subtensor(begin, end-begin);

    // if individual gradients were averages, then need to average again over all subBatches
    auto div = subBatches.size();
    if (options_->get<std::string>("cost-type") == "ce-sum")
      div = 1;
    if(div != 1) {
      using namespace functional;
      Element(_1 = _1 / (float)div, curGrad);
    }

    // actual model update
    shardOpt_[idx]->update(curParam, curGrad);

    if(mvAvg_)
      updateAvgParams(
          paramsAvg_[idx], curParam, scheduler_->numberOfBatches());
  };

  timer::Timer timer;
  comm_->scatterReduce(); // reduce gradients across all devices (globally) into shards
  LOG(info, timer.format(2, "after scatterReduce (has sync): %ws"));
  comm_->foreach(update); // per-shard model-update
  LOG(info, timer.format(2, "after model update (no sync): %ws"));
  comm_->allGather();     // distribute param value shards back
  LOG(info, timer.format(2, "after allGather (has sync): %ws"));

  // cost across all local devices (scheduler will aggregate cross-process)
  float localCost = 0;
  for(auto& c : localDeviceCosts) // localDeviceCosts is already summed up over delay steps
    localCost += c;

  // if localCost is average-based, we need to turn the sum over devices into an average as well
  if(options_->get<std::string>("localCost-type") != "ce-sum")
    localCost /= numSubBatches;

  if(scheduler_) {
    // track and log localCost
    scheduler_->update(localCost, subBatches, mpi_);

    // save intermediate model (and optimizer state) to file
    if(scheduler_->saving())
      save();

    // process valid data set
    // This may save a model as well.
    if(scheduler_->validating()) {
      swapParamsAvg();
      if (isMainProcess())
        scheduler_->validate(graphs_);
      swapParamsAvg();
    }
  }
}

void SyncGraphGroup::load() /*override*/ {
  if(!options_->get<bool>("no-reload")) {
    std::string name = options_->get<std::string>("model");

    if(filesystem::exists(name)) {
      if(scheduler_)
        scheduler_->load(name);

      std::string nameGraph = name;
      if(mvAvg_ && filesystem::exists(name + ".orig.npz"))
        // Load the original parameters from model.npz.orig.npz
        nameGraph += ".orig.npz";

      size_t i = 0;
      for(auto graph : graphs_)
        builders_[i++]->load(graph, nameGraph); // we just load it N times from disk (it'll be in disk cache after the first)

      // @TODO: probably we want to have the list of DeviceIds as an attribute
      std::vector<Ptr<Backend>> backends;
      for(auto graph : graphs_)
        backends.push_back(graph->getBackend());
      shardOpt_[0]->load(name + ".optimizer.npz", shardOpt_, backends,
        [&](const std::vector<float>& data, const OptimizerBase::ScatterStateSetFunc& setFn) {
          comm_->scatterState(data, setFn);
        });
    } else if(options_->has("pretrained-model")) {
      std::string nameInit = options_->get<std::string>("pretrained-model");
      LOG(info,
          "Initialize model weights with the pre-trained model {}",
          nameInit);

      size_t i = 0;
      for(auto graph : graphs_)
        builders_[i++]->load(graph, nameInit, false);
    }
  }
}

void SyncGraphGroup::save(bool final) /*override*/ {
  barrier(); // (for better grouping of log messages)
  LOG(info, "[{}] save() line {}!", this->mpi_->idStr(), __LINE__);
  // do final validation
  if(final && scheduler_) {
    // bring the smoothed model in
    // Note that it is sharded. For multi-node, it is sharded over multiple machines, so this is a network access.
    // Also note that the swap must run on all MPI processes concurrently, although only one actually validates.
    LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
    swapParamsAvg();
    LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
    if (isMainProcess()) // in multi-node, only first MPI process saves the model (they are all identical)
      scheduler_->validate(graphs_, true);
    LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
    swapParamsAvg();
    LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
  }

  std::string name = options_->get<std::string>("model");

  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
  barrier(); // (for better grouping of log messages)
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
  // if smoothing then save original (unsmoothed) parameters as well
  // @TODO: Check whether we are reloading the correct file (the unsmoothed one).
  if(mvAvg_ && paramsAvg_.size() > 0 && isMainProcess()) // only save from one MPI process
    // Save the original parameters in model.npz.orig.npz
    builders_[0]->save(graphs_[0], name + ".orig.npz", true);

  // Temporarily switch to the averaged parameters
  // Note: the smoothed model is sharded across GPUs, and across MPI processes if applicable. This brings it into MPI process[*].device[*]
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
  swapParamsAvg();
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);

  // save main model file
  if (isMainProcess()) { // only save from one MPI process
    // if not overwrite then save a copy with number of updates in the model pathname
    LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
    if(!options_->get<bool>("overwrite") && !final) {
      std::string numberOfBatches
          = scheduler_ ? std::to_string(scheduler_->numberOfBatches())
                       : "unknown";
      std::string nameOverwrite = name;
      nameOverwrite.replace(name.size() - 4, 4, ".iter" + numberOfBatches + ".npz"); // @TODO: use insert?
      builders_[0]->save(graphs_[0], nameOverwrite);
    }
    LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
    // save main model file
    builders_[0]->save(graphs_[0], name, true);
    LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
    // save scheduler-related state
    if (scheduler_)
      scheduler_->save(name);
    LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
  }

  // Switch back to the original parameters
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
  swapParamsAvg();
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);

#if 1 // temporary, for testing of saving distributed models; must be identical to .orig.npz
  if(mvAvg_ && paramsAvg_.size() > 0 && isMainProcess())
    builders_[0]->save(graphs_[0], name + ".orig_after_swapping.npz", true);
#endif
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
  barrier(); // (for better grouping of log messages)
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);

  // persist optimizer state
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
  shardOpt_[0]->save(name + ".optimizer.npz", shardOpt_,
    [&](const OptimizerBase::GatherStateGetFunc& getFn) {
      return comm_->gatherState(getFn);
    },
    isMainProcess());
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);

  barrier(); // (for better grouping of log messages)
  LOG(info, "[{}] save() line {}", this->mpi_->idStr(), __LINE__);
}

}  // namespace marian
<|endoftext|>


<commit_before>/*---------------------------------------------------------------
 * Copyright (c) 1999,2000,2001,2002,2003
 * The Board of Trustees of the University of Illinois
 * All Rights Reserved.
 *---------------------------------------------------------------
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software (Iperf) 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:
 *
 *
 * Redistributions of source code must retain the above
 * copyright notice, this list of conditions and
 * the following disclaimers.
 *
 *
 * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following
 * disclaimers in the documentation and/or other materials
 * provided with the distribution.
 *
 *
 * Neither the names of the University of Illinois, NCSA,
 * nor the names of its contributors may be used to endorse
 * or promote products derived from this Software without
 * specific prior written permission.
 *
 * 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 CONTIBUTORS 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.
 * ________________________________________________________________
 * National Laboratory for Applied Network Research
 * National Center for Supercomputing Applications
 * University of Illinois at Urbana-Champaign
 * http://www.ncsa.uiuc.edu
 * ________________________________________________________________
 *
 * Settings.hpp
 * by Mark Gates <mgates@nlanr.net>
 * &  Ajay Tirumala <tirumala@ncsa.uiuc.edu>
 * -------------------------------------------------------------------
 * Stores and parses the initial values for all the global variables.
 * -------------------------------------------------------------------
 * headers
 * uses
 *   <stdlib.h>
 *   <assert.h>
 * ------------------------------------------------------------------- */

#ifndef SETTINGS_H
#define SETTINGS_H

#include "headers.h"

#include "Thread.hpp"

/* -------------------------------------------------------------------
 * constants
 * ------------------------------------------------------------------- */

// server/client mode
enum ServerMode {
    kMode_Server,
    kMode_Client,
    kMode_Unknown
};

// protocol mode
const bool kMode_UDP    = false;
const bool kMode_TCP    = true;

// termination mode
const bool kMode_Amount = false;  // transmit fixed amount
const bool kMode_Time   = true;   // transmit fixed time

// domain mode
const bool kMode_IPv4 = false;
const bool kMode_IPv6 = true;

class Settings;
extern Settings* gSettings;

/* ------------------------------------------------------------------- */
class Settings {
public:
    // set to defaults
    Settings( void );

    // free associated memory
    ~Settings();

    // parse settings from user's environment variables
    void ParseEnvironment( void );

    // parse settings from app's command line
    void ParseCommandLine( int argc, char **argv );

    // convert to lower case for [KMG]bits/sec
    const void GetLowerCaseArg(const char *,char *);

    // conver to upper case for [KMG]bytes/sec
    const void GetUpperCaseArg(const char *,char *);

    // ---- access settings

    // -b #
    // valid in UDP mode
    double GetUDPRate( void ) const {
        assert( GetProtocolMode() == kMode_UDP );
        return mUDPRate;
    }

    // -c <host>
    // valid in client mode
    const char* GetHost( void ) const {
        assert( GetServerMode() == kMode_Client );
        return mHost;
    }

    // -f [kmKM]
    char GetFormat( void ) const {
        return mFormat;
    }

    // -l #
    int GetBufferLen( void ) const {
        return mBufLen;
    }

    // -m
    // valid in TCP mode
    bool GetPrintMSS( void ) const {
        assert( GetProtocolMode() == kMode_TCP );
        return mPrintMSS;
    }

    // -n #
    // valid in Amount mode (transmit fixed amount of data)
    max_size_t GetAmount( void ) const {
        assert( mAmount > 0 );
        assert( GetTerminationMode() == kMode_Amount );
        return(max_size_t) mAmount;
    }

    // -p #
    unsigned short GetPort( void ) const {
        return mPort;
    }

    // -s or -c
    ServerMode GetServerMode( void ) const {
        return mServerMode;
    }

    // -t #
    // valid in Time mode (transmit for fixed time)
    double GetTime( void ) const {
        assert( mAmount < 0 );
        assert( GetTerminationMode() == kMode_Time );
        return -mAmount;
    }

    // -w #
    int GetTCPWindowSize( void ) const {
        return mTCPWin;
    }

    // ---- more esoteric options

    // -B <host>
    const char* GetLocalhost( void ) const {
        return mLocalhost;
    }

    // -i #
    double GetInterval( void ) const {
        return mInterval;
    }

    // -M #
    // valid in TCP mode
    int GetTCP_MSS( void ) const {
        assert( GetProtocolMode() == kMode_TCP );
        return mMSS;
    }

    // -N
    // valid in TCP mode
    bool GetTCP_Nodelay( void ) const {
        assert( GetProtocolMode() == kMode_TCP );
        return mNodelay;
    }

    // -P #
    // only useful in TCP mode
    int GetClientThreads( void ) const {
        //assert( GetProtocolMode() == kMode_TCP );
        return mThreads;
    }

    // -S #
    int GetTOS( void ) const {
        return mTOS;
    }

    // -T #
    // valid in UDP mode
    u_char GetMcastTTL( void ) const {
        return mTTL;
    }

    // ---- modes

    // differentiate Time and Amount; -t # and -n #
    // note these optimize to just the comparison with zero
    bool GetTerminationMode( void ) const {
        return(mAmount < 0  ?  kMode_Time  :  kMode_Amount);
    }

    // differentiate UDP and TCP; -u or -b # gives UDP
    bool GetProtocolMode( void ) const {
        return(mUDPRate == 0  ?  kMode_TCP  :  kMode_UDP);
    }

    // whether the server runs as a daemon or not
    bool GetDaemonMode(void) const {
        return mDaemon;
    }

    // Whether the client must suggest the window size or not
    bool GetSuggestWin(void) const {
        return mSuggestWin;
    }

    // Set the interval time
    void SetInterval(double interval) {
        mInterval = interval;
    }

    // Set the file input status
    void SetFileInput(bool status) {
        mFileInput = status;
    }

    // Whether the input is the default stream or a
    // file stream
    bool GetFileInput(void) const {
        return mFileInput;
    }

    // return the file name if the input is through a
    // file stream
    char *GetFileName(void) const {
        if ( mFileInput )
            return mFileName;
        return NULL;
    }

    // return whether the input is from stdin
    bool GetStdin(void) const {
        return mStdin;
    }

    // file stream
    bool GetFileOutput(void) const {
        if ( mStdout )
            return false;
        return true;
    }

    // return the file name if the output is through a
    // file stream
    char *GetOutputFileName(void) const {
        if ( !mStdout )
            return mOutputFileName;
        return NULL;
    }

    // whether win32 service should be removed or not
    bool GetRemoveService(void) const {
        return mRemoveService;
    }

    // IPv4 or IPv6 domain
    bool GetDomain(void) const {
        return mDomain;
    }

protected:
    void Interpret( char option, const char *optarg );

    // here instead of listing by option order (as elsewhere)
    // I list by type so that the structure alignment will be nice

    char*  mHost;      // -c
    char*  mLocalhost; // -B
    char*  mFileName;  // -F
    char*  mOutputFileName; // -o

    double mUDPRate;   // -b
    double mAmount;    // -n or -t
    double mInterval;  // -i

    int    mBufLen;    // -l
    int    mTCPWin;    // -w
    int    mMSS;       // -m
    int    mThreads;   // -P
    int    mTOS;       // -S

    unsigned short mPort; // -p

    char   mFormat;    // -f
    u_char mTTL;       // --ttl

    ServerMode mServerMode; // -s or -c

    bool   mPrintMSS;  // -M
    bool   mNodelay;   // -N
    bool   mBufLenSet; // if -l was specified.
                       // UDP and TCP have different BufLen defaults.
    bool   mDaemon;    // -d
    bool   mSuggestWin;
    bool   mFileInput; // -F or -I
    bool   mStdin;     // -I
    bool   mStdout;     // -o
    bool   mDomain;    // -V
    bool   mRemoveService; // -R

}; // end class Settings

#endif // SETTINGS_H
<commit_msg>Import from CVS Thu Feb 27 22:35:24 2003 -0600<commit_after>/*---------------------------------------------------------------
 * Copyright (c) 1999,2000,2001,2002,2003
 * The Board of Trustees of the University of Illinois
 * All Rights Reserved.
 *---------------------------------------------------------------
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software (Iperf) 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:
 *
 *
 * Redistributions of source code must retain the above
 * copyright notice, this list of conditions and
 * the following disclaimers.
 *
 *
 * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following
 * disclaimers in the documentation and/or other materials
 * provided with the distribution.
 *
 *
 * Neither the names of the University of Illinois, NCSA,
 * nor the names of its contributors may be used to endorse
 * or promote products derived from this Software without
 * specific prior written permission.
 *
 * 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 CONTIBUTORS 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.
 * ________________________________________________________________
 * National Laboratory for Applied Network Research
 * National Center for Supercomputing Applications
 * University of Illinois at Urbana-Champaign
 * http://www.ncsa.uiuc.edu
 * ________________________________________________________________
 *
 * Settings.hpp
 * by Mark Gates <mgates@nlanr.net>
 * &  Ajay Tirumala <tirumala@ncsa.uiuc.edu>
 * -------------------------------------------------------------------
 * Stores and parses the initial values for all the global variables.
 * -------------------------------------------------------------------
 * headers
 * uses
 *   <stdlib.h>
 *   <assert.h>
 * ------------------------------------------------------------------- */

#ifndef SETTINGS_H
#define SETTINGS_H

#include "headers.h"

#include "Thread.hpp"

/* -------------------------------------------------------------------
 * constants
 * ------------------------------------------------------------------- */

// server/client mode
enum ServerMode {
    kMode_Server,
    kMode_Client,
    kMode_Unknown
};

// test mode
enum TestMode {
    kTest_Normal,
    kTest_DualTest,
    kTest_TradeOff,
    kTest_Unknown
};

// protocol mode
const bool kMode_UDP    = false;
const bool kMode_TCP    = true;

// termination mode
const bool kMode_Amount = false;  // transmit fixed amount
const bool kMode_Time   = true;   // transmit fixed time

// domain mode
const bool kMode_IPv4 = false;
const bool kMode_IPv6 = true;

class Settings;

/*
 * The ext_Settings is a structure that holds all
 * options for a given execution of either a client
 * or server. By using this structure rather than
 * a global structure or class we can have multiple
 * clients or servers running with different settings.
 */
struct ext_Settings {
    char*  mFileName;               // -F
    char*  mHost;                   // -c
    char*  mLocalhost;              // -B
    char*  mOutputFileName;         // -o
    double mInterval;               // -i
    int mAmount;                    // -n or -t
    int mBufLen;                    // -l
    int mMSS;                       // -M
    int mTCPWin;                    // -w
    int mThreads;                   // -P
    int mTOS;                       // -S
    int mUDPRate;                   // -b or -u
    ServerMode mServerMode;         // -s or -c
    TestMode mMode;                 // -r or -d
    unsigned short mListenPort;     // -L
    unsigned short mPort;           // -p
    char   mFormat;                 // -f
    u_char mTTL;                    // -T
    bool   mBufLenSet;              // -l
    bool   mCompat;                 // -C
    bool   mDaemon;                 // -D
    bool   mDomain;                 // -V
    bool   mFileInput;              // -F or -I
    bool   mNodelay;                // -N
    bool   mPrintMSS;               // -m
    bool   mRemoveService;          // -R
    bool   mStdin;                  // -I
    bool   mStdout;                 // -o
    bool   mSuggestWin;             // -W
};

#define HEADER_VERSION1 0x80000000
#define RUN_NOW         0x00000001

// used to reference the 4 byte ID number we place in UDP datagrams
// use int32_t if possible, otherwise a 32 bit bitfield (e.g. on J90)
struct UDP_datagram {
#ifdef HAVE_INT32_T
    int32_t id;
    u_int32_t tv_sec;
    u_int32_t tv_usec;
#else
    signed   int id      : 32;
    unsigned int tv_sec  : 32;
    unsigned int tv_usec : 32;
#endif
};

/*
 * The client_hdr structure is sent from clients
 * to servers to alert them of things that need
 * to happen. Order must be perserved in all
 * future releases for backward compatibility.
 * 1.7 has flags, numThreads, mPort, and bufferlen
 */
struct client_hdr {

#ifdef HAVE_INT32_T

    /*
     * flags is a bitmap for different options
     * the most significant bits are for determining
     * which information is available. So 1.7 uses
     * 0x80000000 and the next time information is added
     * the 1.7 bit will be set and 0x40000000 will be
     * set signifying additional information. If no
     * information bits are set then the header is ignored.
     * The lowest order diferentiates between dualtest and
     * tradeoff modes, wheither the speaker needs to start
     * immediately or after the audience finishes.
     */
    int32_t flags;
    int32_t numThreads;
    int32_t mPort;
    int32_t bufferlen;
    int32_t mWinBand;
    int32_t mAmount;
#else
    signed int flags      : 32;
    signed int numThreads : 32;
    signed int mPort      : 32;
    signed int bufferlen  : 32;
    signed int mWinBand   : 32;
    signed int mAmount    : 32;
#endif
};

/*
 * The server_hdr structure facilitates the server
 * report of jitter and loss on the client side.
 * It piggy_backs on the existing clear to close
 * packet.
 */
struct server_hdr {

#ifdef HAVE_INT32_T

    /*
     * flags is a bitmap for different options
     * the most significant bits are for determining
     * which information is available. So 1.7 uses
     * 0x80000000 and the next time information is added
     * the 1.7 bit will be set and 0x40000000 will be
     * set signifying additional information. If no
     * information bits are set then the header is ignored.
     */
    int32_t flags;
    int32_t total_len1;
    int32_t total_len2;
    int32_t stop_sec;
    int32_t stop_usec;
    int32_t error_cnt;
    int32_t outorder_cnt;
    int32_t datagrams;
    int32_t jitter1;
    int32_t jitter2;
#else
    signed int flags        : 32;
    signed int total_len1   : 32;
    signed int total_len2   : 32;
    signed int stop_sec     : 32;
    signed int stop_usec    : 32;
    signed int error_cnt    : 32;
    signed int outorder_cnt : 32;
    signed int datagrams    : 32;
    signed int jitter1      : 32;
    signed int jitter2      : 32;
#endif

};

/* ------------------------------------------------------------------- */
class Settings {
public:
    // set to defaults
    Settings( ext_Settings* main );

    // free associated memory
    ~Settings();

    // parse settings from user's environment variables
    void ParseEnvironment( void );

    // parse settings from app's command line
    void ParseCommandLine( int argc, char **argv );

    // convert to lower case for [KMG]bits/sec
    const void GetLowerCaseArg(const char *,char *);

    // conver to upper case for [KMG]bytes/sec
    const void GetUpperCaseArg(const char *,char *);

    // generate settings for listener instance
    static void GenerateListenerSettings( ext_Settings *old, ext_Settings **listener);

    // generate settings for speaker instance
    static void GenerateSpeakerSettings( ext_Settings *old, ext_Settings **speaker,
                                         client_hdr *hdr, sockaddr* peer );

    // generate client header for server
    static void GenerateClientHdr( ext_Settings *old, client_hdr *hdr );

    // ---- access settings

    // -b #
    // valid in UDP mode
    double GetUDPRate( void ) const {
        assert( GetProtocolMode() == kMode_UDP );
        return mExtSettings->mUDPRate;
    }

    // -c <host>
    // valid in client mode
    const char* GetHost( void ) const {
        assert( mExtSettings->mServerMode == kMode_Client );
        return mExtSettings->mHost;
    }

    // -f [kmKM]
    char GetFormat( void ) const {
        return mExtSettings->mFormat;
    }

    // -l #
    int GetBufferLen( void ) const {
        return mExtSettings->mBufLen;
    }

    // -m
    // valid in TCP mode
    bool GetPrintMSS( void ) const {
        assert( GetProtocolMode() == kMode_TCP );
        return mExtSettings->mPrintMSS;
    }

    // -n #
    // valid in Amount mode (transmit fixed amount of data)
    max_size_t GetAmount( void ) const {
        assert( mExtSettings->mAmount > 0 );
        assert( GetTerminationMode() == kMode_Amount );
        return (max_size_t) mExtSettings->mAmount;
    }

    // -p #
    unsigned short GetPort( void ) const {
        return mExtSettings->mPort;
    }

    // -L #
    unsigned short GetListenPort( void ) const {
        return mExtSettings->mListenPort;
    }

    // -s or -c
    ServerMode GetServerMode( void ) const {
        return mExtSettings->mServerMode;
    }

    // -d or -r
    TestMode GetTestingMode( void ) const {
        return mExtSettings->mMode;
    }

    // -t #
    // valid in Time mode (transmit for fixed time)
    double GetTime( void ) const {
        assert( mExtSettings->mAmount < 0 );
        return (-mExtSettings->mAmount) / 100.0;
    }

    // -w #
    int GetTCPWindowSize( void ) const {
        return mExtSettings->mTCPWin;
    }

    // ---- more esoteric options

    // -B <host>
    const char* GetLocalhost( void ) const {
        return mExtSettings->mLocalhost;
    }

    // -i #
    double GetInterval( void ) const {
        return mExtSettings->mInterval;
    }

    // -M #
    // valid in TCP mode
    int GetTCP_MSS( void ) const {
        assert( GetProtocolMode() == kMode_TCP );
        return mExtSettings->mMSS;
    }

    // -N
    // valid in TCP mode
    bool GetTCP_Nodelay( void ) const {
        assert( GetProtocolMode() == kMode_TCP );
        return mExtSettings->mNodelay;
    }

    // -P #
    int GetClientThreads( void ) const {
        return mExtSettings->mThreads;
    }

    // -S #
    int GetTOS( void ) const {
        return mExtSettings->mTOS;
    }

    // -T #
    // valid in UDP mode
    u_char GetMcastTTL( void ) const {
        return mExtSettings->mTTL;
    }

    // ---- modes

    // differentiate Time and Amount; -t # and -n #
    // note these optimize to just the comparison with zero
    bool GetTerminationMode( void ) const {
        return ( mExtSettings->mAmount < 0  ?  kMode_Time  :  kMode_Amount );
    }

    // differentiate UDP and TCP; -u or -b # gives UDP
    bool GetProtocolMode( void ) const {
        return ( mExtSettings->mUDPRate == 0  ?  kMode_TCP  :  kMode_UDP );
    }

    // whether the server runs as a daemon or not
    bool GetDaemonMode(void) const {
        return mExtSettings->mDaemon;
    }

    // whether running in compatibility mode or not
    bool GetCompatMode(void) const {
        return mExtSettings->mCompat;
    }

    // Whether the client must suggest the window size or not
    bool GetSuggestWin(void) const {
        return mExtSettings->mSuggestWin;
    }

    // Set the interval time
    void SetInterval(double interval) {
        mExtSettings->mInterval = interval;
    }

    // Set the file input status
    void SetFileInput(bool status) {
        mExtSettings->mFileInput = status;
    }

    // Whether the input is the default stream or a
    // file stream
    bool GetFileInput(void) const {
        return mExtSettings->mFileInput;
    }

    // return the file name if the input is through a
    // file stream
    char *GetFileName(void) const {
        if ( mExtSettings->mFileInput )
            return mExtSettings->mFileName;
        return NULL;
    }

    // return whether the input is from stdin
    bool GetStdin(void) const {
        return mExtSettings->mStdin;
    }

    // file stream
    bool GetFileOutput(void) const {
        if ( mExtSettings->mStdout )
            return false;
        return true;
    }

    // return the file name if the output is through a
    // file stream
    char *GetOutputFileName(void) const {
        if ( !mExtSettings->mStdout )
            return mExtSettings->mOutputFileName;
        return NULL;
    }

    // whether win32 service should be removed or not
    bool GetRemoveService(void) const {
        return mExtSettings->mRemoveService;
    }

    // IPv4 or IPv6 domain
    bool GetDomain(void) const {
        return mExtSettings->mDomain;
    }

protected:
    void Interpret( char option, const char *optarg );

    ext_Settings* mExtSettings;

}; // end class Settings

#endif // SETTINGS_H
<|endoftext|>


<commit_before>#include "unittest/gtest.hpp"

#include "arch/runtime/context_switching.hpp"

namespace unittest {

static void noop(void) {
}

TEST(ContextSwitchingTest, ContextRefSemantics) {
    context_ref_t nil_ref;
    EXPECT_TRUE(nil_ref.is_nil());
}

TEST(ContextSwitchingTest, CreateArtificialStack) {
    artificial_stack_t a(&noop, 1024*1024);
    EXPECT_FALSE(a.context.is_nil());
}

/* Thread-local variables for use in test functions, because we cannot pass a
`void*` to the test functions... */

static __thread context_ref_t
    *original_context = NULL,
    *artificial_stack_1_context = NULL,
    *artificial_stack_2_context = NULL;
static __thread int test_int;

static void switch_context_test(void) {
    test_int++;
    context_switch(artificial_stack_1_context, original_context);
    test_int += 2;
    context_switch(artificial_stack_1_context, original_context);
    test_int += 3;
    context_switch(artificial_stack_1_context, original_context);
    /* This will never get run */
    test_int += 10000;
}

TEST(ContextSwitchingTest, SwitchToContextRepeatedly) {
    original_context = new context_ref_t;
    test_int = 5;
    {
        artificial_stack_t a(&switch_context_test, 1024*1024);
        artificial_stack_1_context = &a.context;

        /* `context_switch` will cause `switch_context_test` to be run, which
        will increment `test_int` and then switch back from `src_context` to
        `dest_context`. */
        context_switch(original_context, artificial_stack_1_context);
        context_switch(original_context, artificial_stack_1_context);
        context_switch(original_context, artificial_stack_1_context);

        EXPECT_FALSE(a.context.is_nil());
    }
    EXPECT_EQ(test_int, 11);
    delete original_context;
}

static void first_switch(void) {
    test_int++;
    context_switch(artificial_stack_1_context, artificial_stack_2_context);
}

static void second_switch(void) {
    test_int++;
    context_switch(artificial_stack_2_context, original_context);
}

TEST(ContextSwitchingTest, SwitchBetweenContexts) {
    original_context = new context_ref_t;
    test_int = 99;
    {
        artificial_stack_t a1(&first_switch, 1024*1024);
        artificial_stack_t a2(&second_switch, 1024*1024);
        artificial_stack_1_context = &a1.context;
        artificial_stack_2_context = &a2.context;

        context_switch(original_context, artificial_stack_1_context);
    }
    EXPECT_EQ(test_int, 101);
    delete original_context;
}

}   /* namespace unittest */
<commit_msg>Set thread-local vars to NULL when done using them in context_switching unit test.<commit_after>#include "unittest/gtest.hpp"

#include "arch/runtime/context_switching.hpp"

namespace unittest {

static void noop(void) {
}

TEST(ContextSwitchingTest, ContextRefSemantics) {
    context_ref_t nil_ref;
    EXPECT_TRUE(nil_ref.is_nil());
}

TEST(ContextSwitchingTest, CreateArtificialStack) {
    artificial_stack_t a(&noop, 1024*1024);
    EXPECT_FALSE(a.context.is_nil());
}

/* Thread-local variables for use in test functions, because we cannot pass a
`void*` to the test functions... */

static __thread context_ref_t
    *original_context = NULL,
    *artificial_stack_1_context = NULL,
    *artificial_stack_2_context = NULL;
static __thread int test_int;

static void switch_context_test(void) {
    test_int++;
    context_switch(artificial_stack_1_context, original_context);
    test_int += 2;
    context_switch(artificial_stack_1_context, original_context);
    test_int += 3;
    context_switch(artificial_stack_1_context, original_context);
    /* This will never get run */
    test_int += 10000;
}

TEST(ContextSwitchingTest, SwitchToContextRepeatedly) {
    original_context = new context_ref_t;
    test_int = 5;
    {
        artificial_stack_t a(&switch_context_test, 1024*1024);
        artificial_stack_1_context = &a.context;

        /* `context_switch` will cause `switch_context_test` to be run, which
        will increment `test_int` and then switch back from `src_context` to
        `dest_context`. */
        context_switch(original_context, artificial_stack_1_context);
        context_switch(original_context, artificial_stack_1_context);
        context_switch(original_context, artificial_stack_1_context);

        EXPECT_FALSE(a.context.is_nil());
    }
    EXPECT_EQ(test_int, 11);
    delete original_context;
    original_context = NULL;
}

static void first_switch(void) {
    test_int++;
    context_switch(artificial_stack_1_context, artificial_stack_2_context);
}

static void second_switch(void) {
    test_int++;
    context_switch(artificial_stack_2_context, original_context);
}

TEST(ContextSwitchingTest, SwitchBetweenContexts) {
    original_context = new context_ref_t;
    test_int = 99;
    {
        artificial_stack_t a1(&first_switch, 1024*1024);
        artificial_stack_t a2(&second_switch, 1024*1024);
        artificial_stack_1_context = &a1.context;
        artificial_stack_2_context = &a2.context;

        context_switch(original_context, artificial_stack_1_context);
    }
    EXPECT_EQ(test_int, 101);
    delete original_context;
    original_context = NULL;
}

}   /* namespace unittest */
<|endoftext|>