<commit_before>/* The MIT License

Copyright (c) 2011 Sahab Yazdani

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifdef WIN32
// needed by opengl
#include <windows.h>

// remove stupidness
#undef min
#undef max

#endif // WIN32

// stl
#include <string>
#include <memory>
#include <iostream>
#include <fstream>

// boost
#include <boost/timer.hpp>

// SDL
#include <SDL.h>

// OpenGL
#include <GL/gl.h>
#include <GL/glu.h>

// local
#include "bitmap.h"
#include "stippler.h"
#include "cpustippler.h"
#include "gpustippler.h"
#include "parse_arguments.h"
#include "guicon.h"

#ifdef WIN32
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) {
#else
int main( int argc, char *argv[] ) {
#endif // WIN32
#ifdef WIN32
	int argc = __argc;
	char **argv = __argv;

	RedirectIOToConsole();
#endif // WIN32
	using std::auto_ptr;
	using std::exception;
	using std::ofstream;
	using std::cout;
	using std::endl;
	using boost::timer;

	auto_ptr<StipplingParameters> parameters;

	try {
		parameters = parseArguments( argc, argv );
	} catch ( exception ) {
		return -1;
	}

	::SDL_Init( SDL_INIT_VIDEO );

	::SDL_WM_SetCaption( "Weighted Voronoi Stippling", "Weighted Voronoi Stippling" );

	::SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
	::SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
	::SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
	::SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
	::SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24 );
	::SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );

	::SDL_Surface *screen = ::SDL_SetVideoMode( 640, 480, 32, SDL_OPENGL | SDL_HWSURFACE );

	::glClearColor( 0.0, 0.0, 0.0, 0.0 );
	::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	::SDL_GL_SwapBuffers();

	auto_ptr<Stippler> stippler;

	ofstream log;
	if ( parameters->createLogs ) {
		log.open( "log.txt" );
	}

	if ( parameters->algorithm == StipplingParameters::CPU ) {
		if ( parameters->createLogs ) {
			log << "Using CPU Stippler." << endl;
			cout << "Using CPU Stippler." << endl;
		}
		stippler = auto_ptr<Stippler>( new CPUStippler( parameters->inputFile, parameters->points ) );
	} else {
		if ( parameters->createLogs ) {
			log << "Using GPU Stippler." << endl;
			cout << "Using GPU Stippler." << endl;
		}
		stippler = auto_ptr<Stippler>( new GPUStippler( parameters->inputFile, parameters->points ) );
	}

	if ( parameters->createLogs ) {
		log << "Generating " << parameters->points << " stipples." << endl;
		log << "Displacement Threshold is " << parameters->threshold << "." << endl;
		cout << "Generating " << parameters->points << " stipples." << endl;
		cout << "Displacement Threshold is " << parameters->threshold << "." << endl;
	}

	int iteration = 0;
	float t = parameters->threshold + 1.0f;
	do {
		timer profiler;

		stippler->distribute();

		if ( parameters->createLogs ) {
			log << "Iteration " << (++iteration) << " completed in " << profiler.elapsed() << " seconds." << endl;
			cout << "Iteration " << iteration << " completed in " << profiler.elapsed() << " seconds." << endl;
		}

		stippler->paint();

		::SDL_GL_SwapBuffers();

		t = stippler->getAverageDisplacement();

		if ( parameters->createLogs ) {
			log << "Current Displacement: " << t << endl;
			cout << "Current Displacement: " << t << endl;
		}
	} while ( t > parameters->threshold );

	// render final result to SVG
	stippler->render( parameters->outputFile );

	if ( parameters->createLogs ) {
		log.close();
	}

	::SDL_Quit();

	return 0;
}
<commit_msg>Add percentage done calculation.<commit_after>/* The MIT License

Copyright (c) 2011 Sahab Yazdani

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifdef WIN32
// needed by opengl
#include <windows.h>

// remove stupidness
#undef min
#undef max

#endif // WIN32

// stl
#include <string>
#include <memory>
#include <iostream>
#include <iomanip>
#include <fstream>

// boost
#include <boost/timer.hpp>

// SDL
#include <SDL.h>

// OpenGL
#include <GL/gl.h>
#include <GL/glu.h>

// local
#include "bitmap.h"
#include "stippler.h"
#include "cpustippler.h"
#include "gpustippler.h"
#include "parse_arguments.h"
#include "guicon.h"

#ifdef WIN32
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) {
#else
int main( int argc, char *argv[] ) {
#endif // WIN32
#ifdef WIN32
	int argc = __argc;
	char **argv = __argv;

	RedirectIOToConsole();
#endif // WIN32
	using std::auto_ptr;
	using std::exception;
	using std::ofstream;
	using std::cout;
	using std::cerr;
	using std::endl;
	using std::setprecision;
	using std::setiosflags;
	using std::ios;
	using boost::timer;

	auto_ptr<StipplingParameters> parameters;

	try {
		parameters = parseArguments( argc, argv );
		if (parameters.get() == NULL) {
			return 0;
		}
	} catch ( exception e ) {
		return -1;
	}

	::SDL_Init( SDL_INIT_VIDEO );

	::SDL_WM_SetCaption( "Weighted Voronoi Stippling", "Weighted Voronoi Stippling" );

	::SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
	::SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
	::SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
	::SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
	::SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24 );
	::SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );

	::SDL_Surface *screen = ::SDL_SetVideoMode( 640, 480, 32, SDL_OPENGL | SDL_HWSURFACE );

	::glClearColor( 0.0, 0.0, 0.0, 0.0 );
	::glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	::SDL_GL_SwapBuffers();

	auto_ptr<Stippler> stippler;

	ofstream log;
	if ( parameters->createLogs ) {
		log.open( "log.txt" );
	}

	try {
		if ( parameters->algorithm == StipplingParameters::CPU ) {
			if ( parameters->createLogs ) {
				log << "Using CPU Stippler." << endl;
				cout << "Using CPU Stippler." << endl;
			}
			stippler = auto_ptr<Stippler>( new CPUStippler( parameters->inputFile, parameters->points ) );
			if ( parameters->useColour ) {
				stippler->useColour();
			}
		} else {
			if ( parameters->createLogs ) {
				log << "Using GPU Stippler." << endl;
				cout << "Using GPU Stippler." << endl;
			}
			stippler = auto_ptr<Stippler>( new GPUStippler( parameters->inputFile, parameters->points ) );
			if ( parameters->useColour ) {
				stippler->useColour();
			}
		}
	} catch ( exception e ) {
		cerr << e.what() << endl;

		return -1;
	}

	if ( parameters->createLogs ) {
		log << "Generating " << parameters->points << " stipples." << endl;
		log << "Displacement Threshold is " << parameters->threshold << "." << endl;
		cout << "Generating " << parameters->points << " stipples." << endl;
		cout << "Displacement Threshold is " << parameters->threshold << "." << endl;
	}

	int iteration = 0;
	float t = parameters->threshold + 1.0f;
	do {
		timer profiler;

		stippler->distribute();

		if ( parameters->createLogs ) {
			log << "Iteration " << (++iteration) << " completed in " << profiler.elapsed() << " seconds." << endl;
			cout << "Iteration " << iteration << " completed in " << profiler.elapsed() << " seconds." << endl;
		}

		stippler->paint();

		::SDL_GL_SwapBuffers();

		t = stippler->getAverageDisplacement();

		if ( parameters->createLogs ) {
			log << "Current Displacement: " << t << endl;
			cout << "Current Displacement: " << t << endl;
		}

		cout << setiosflags(ios::fixed) << setprecision(2) << (parameters->threshold / t * 100) << "% Complete" << endl;
	} while ( t > parameters->threshold );

	// render final result to SVG
	try {
		stippler->render( parameters->outputFile );
	} catch (exception e) {
		cerr << e.what();
	}

	if ( parameters->createLogs ) {
		log.close();
	}

	::SDL_Quit();

	return 0;
}
<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS internatiodel (1.18.258); FILE MERGED 2006/01/20 15:17:30 er 1.18.258.2: RESYNC: (1.18-1.19); FILE MERGED 2005/06/24 13:11:24 er 1.18.258.1: #i50205# get rid of class International<commit_after><|endoftext|>


<commit_before>/******************************************************************************
** Copyright (c) 2014-2015, Intel Corporation                                **
** All rights reserved.                                                      **
**                                                                           **
** Redistribution and use in source and binary forms, with or without        **
** modification, are permitted provided that the following conditions        **
** are met:                                                                  **
** 1. Redistributions of source code must retain the above copyright         **
**    notice, this list of conditions and the following disclaimer.          **
** 2. Redistributions in binary form must reproduce the above copyright      **
**    notice, this list of conditions and the following disclaimer in the    **
**    documentation and/or other materials provided with the distribution.   **
** 3. Neither the name of the copyright holder 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      **
** HOLDER 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.              **
******************************************************************************/
/* Hans Pabst (Intel Corp.)
******************************************************************************/
#include "libxstream_event.hpp"
#include "libxstream_capture.hpp"

#include <algorithm>

#if defined(LIBXSTREAM_OFFLOAD)
# include <offload.h>
#endif

// allows to wait for an event issued prior to the pending signal
//#define LIBXSTREAM_EVENT_WAIT_PAST
// alternative wait routine; waits until the effect occurred
//#define LIBXSTREAM_EVENT_WAIT_OCCURRED

/*static*/void libxstream_event::enqueue(int thread, libxstream_stream& stream, libxstream_event::slot_type slots[], size_t& expected, bool reset)
{
#if defined(LIBXSTREAM_DEBUG)
  LIBXSTREAM_ASSERT((LIBXSTREAM_MAX_NDEVICES * LIBXSTREAM_MAX_NSTREAMS) > ((reset && 0 < expected) ? (expected - 1) : expected));
#endif

  if (reset) {
#if defined(LIBXSTREAM_DEBUG)
    std::fill_n(slots, LIBXSTREAM_MAX_NDEVICES * LIBXSTREAM_MAX_NSTREAMS, slot_type());
#endif
    expected = 0;
  }

  slot_type& slot = slots[expected];
  slot = slot_type(thread, stream);
  ++expected;
}

/*static*/void libxstream_event::update(int thread, libxstream_event::slot_type& slot)
{
  const libxstream_signal pending_slot = slot.pending();

  if (0 != pending_slot) {
    const libxstream_signal pending_stream = slot.stream().pending(thread);

    if (0 != pending_stream) {
#if defined(LIBXSTREAM_EVENT_WAIT_PAST)
      const libxstream_signal signal = pending_slot;
#else
      const libxstream_signal signal = pending_stream;
#endif
#if defined(LIBXSTREAM_OFFLOAD)
      if (0 != _Offload_signaled(slot.stream().device(), reinterpret_cast<void*>(signal)))
#endif
      {
        if (signal == pending_stream) {
          slot.stream().pending(thread, 0);
        }
        slot.pending(0);
      }
    }
    else {
      slot.pending(0);
    }
  }
}

libxstream_event::slot_type::slot_type(int thread, libxstream_stream& stream)
  : m_stream(&stream) // no need to lock the stream
  , m_pending(stream.pending(thread))
{}

libxstream_event::libxstream_event()
  : m_expected(0)
{}

size_t libxstream_event::expected() const
{
  LIBXSTREAM_ASSERT((LIBXSTREAM_MAX_NDEVICES * LIBXSTREAM_MAX_NSTREAMS) >= m_expected);
  return m_expected;
}

void libxstream_event::enqueue(libxstream_stream& stream, bool reset)
{
  LIBXSTREAM_ASYNC_BEGIN(stream, m_slots, &m_expected, static_cast<libxstream_bool>(reset ? LIBXSTREAM_TRUE : LIBXSTREAM_FALSE))
  {
    libxstream_event::enqueue(thread(), *LIBXSTREAM_ASYNC_STREAM, ptr<slot_type,0>(), *ptr<size_t,1>(), val<bool,2>());
  }
  LIBXSTREAM_ASYNC_END(LIBXSTREAM_CALL_UNLOCK);
}

int libxstream_event::query(bool& occurred, libxstream_stream* stream) const
{
  int result = LIBXSTREAM_ERROR_NONE;

  LIBXSTREAM_ASYNC_BEGIN(stream, &result, &m_expected, m_slots, &occurred)
  {
    const size_t expected = *ptr<const size_t,1>();
    slot_type *const slots = ptr<slot_type,2>();
    bool occurred = true; // everythig "occurred" if nothing is expected

    if (LIBXSTREAM_ASYNC_STREAM) {
      *ptr<int,0>() = LIBXSTREAM_ASYNC_STREAM->reset();
    }

    for (size_t i = 0; i < expected; ++i) {
      slot_type& slot = slots[i];

      if (slot.match(LIBXSTREAM_ASYNC_STREAM) && 0 != slot.pending()) {
        libxstream_event::update(thread(), slot);
        occurred = occurred && 0 == slot.pending();
      }
    }

    *ptr<bool,3>() = occurred;
  }
  LIBXSTREAM_ASYNC_END(LIBXSTREAM_CALL_WAIT);

  return result;
}

int libxstream_event::wait(libxstream_stream* stream)
{
  int result = LIBXSTREAM_ERROR_NONE;

  LIBXSTREAM_ASYNC_BEGIN(stream, &result, &m_expected, m_slots)
  {
    size_t& expected = *ptr<size_t,1>();
    slot_type *const slots = ptr<slot_type,2>();
    size_t completed = 0;

    if (LIBXSTREAM_ASYNC_STREAM) {
      *ptr<int,0>() = LIBXSTREAM_ASYNC_STREAM->reset();
    }

    for (size_t i = 0; i < expected; ++i) {
      slot_type& slot = slots[i];
      const libxstream_signal pending_stream = slot.stream().pending(thread());
      const libxstream_signal pending_slot = slot.pending();

      if (slot.match(LIBXSTREAM_ASYNC_STREAM) && 0 != pending_stream && 0 != pending_slot) {
#if defined(LIBXSTREAM_EVENT_WAIT_OCCURRED)
        do { // spin/yield
          libxstream_event::update(thread(), slot);
          this_thread_yield();
        }
        while(0 != slot.pending());
#else
# if defined(LIBXSTREAM_EVENT_WAIT_PAST)
        const libxstream_signal signal = pending_slot;
# else
        const libxstream_signal signal = pending_stream;
# endif
# if defined(LIBXSTREAM_OFFLOAD) && defined(LIBXSTREAM_ASYNC) && (0 != (2*LIBXSTREAM_ASYNC+1)/2)
        if (0 <= slot.stream().device()) {
          LIBXSTREAM_ASYNC_DEVICE_UPDATE(slot.stream().device());
#         pragma offload_wait LIBXSTREAM_ASYNC_TARGET wait(signal)
        }
# endif
        if (signal == pending_stream) {
          slot.stream().pending(thread(), 0);
        }
#endif
        ++completed;
      }
    }

    LIBXSTREAM_ASSERT(completed <= expected);
    expected -= completed;
  }
  LIBXSTREAM_ASYNC_END(LIBXSTREAM_CALL_WAIT | LIBXSTREAM_CALL_UNLOCK);

  return result;
}
<commit_msg>Fixed link stage when compiling with -offload-attribute-target=mic.<commit_after>/******************************************************************************
** Copyright (c) 2014-2015, Intel Corporation                                **
** All rights reserved.                                                      **
**                                                                           **
** Redistribution and use in source and binary forms, with or without        **
** modification, are permitted provided that the following conditions        **
** are met:                                                                  **
** 1. Redistributions of source code must retain the above copyright         **
**    notice, this list of conditions and the following disclaimer.          **
** 2. Redistributions in binary form must reproduce the above copyright      **
**    notice, this list of conditions and the following disclaimer in the    **
**    documentation and/or other materials provided with the distribution.   **
** 3. Neither the name of the copyright holder 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      **
** HOLDER 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.              **
******************************************************************************/
/* Hans Pabst (Intel Corp.)
******************************************************************************/
#include "libxstream_event.hpp"
#include "libxstream_capture.hpp"

#include <algorithm>

#if defined(LIBXSTREAM_OFFLOAD)
# include <offload.h>
#endif

// allows to wait for an event issued prior to the pending signal
//#define LIBXSTREAM_EVENT_WAIT_PAST
// alternative wait routine; waits until the effect occurred
//#define LIBXSTREAM_EVENT_WAIT_OCCURRED

/*static*/void libxstream_event::enqueue(int thread, libxstream_stream& stream, libxstream_event::slot_type slots[], size_t& expected, bool reset)
{
#if defined(LIBXSTREAM_DEBUG)
  LIBXSTREAM_ASSERT((LIBXSTREAM_MAX_NDEVICES * LIBXSTREAM_MAX_NSTREAMS) > ((reset && 0 < expected) ? (expected - 1) : expected));
#endif

  if (reset) {
#if defined(LIBXSTREAM_DEBUG)
    std::fill_n(slots, LIBXSTREAM_MAX_NDEVICES * LIBXSTREAM_MAX_NSTREAMS, slot_type());
#endif
    expected = 0;
  }

  slot_type& slot = slots[expected];
  slot = slot_type(thread, stream);
  ++expected;
}

/*static*/void libxstream_event::update(int thread, libxstream_event::slot_type& slot)
{
  const libxstream_signal pending_slot = slot.pending();

  if (0 != pending_slot) {
    const libxstream_signal pending_stream = slot.stream().pending(thread);

    if (0 != pending_stream) {
#if defined(LIBXSTREAM_EVENT_WAIT_PAST)
      const libxstream_signal signal = pending_slot;
#else
      const libxstream_signal signal = pending_stream;
#endif
#if defined(LIBXSTREAM_OFFLOAD) && !defined(__MIC__)
      if (0 != _Offload_signaled(slot.stream().device(), reinterpret_cast<void*>(signal)))
#endif
      {
        if (signal == pending_stream) {
          slot.stream().pending(thread, 0);
        }
        slot.pending(0);
      }
    }
    else {
      slot.pending(0);
    }
  }
}

libxstream_event::slot_type::slot_type(int thread, libxstream_stream& stream)
  : m_stream(&stream) // no need to lock the stream
  , m_pending(stream.pending(thread))
{}

libxstream_event::libxstream_event()
  : m_expected(0)
{}

size_t libxstream_event::expected() const
{
  LIBXSTREAM_ASSERT((LIBXSTREAM_MAX_NDEVICES * LIBXSTREAM_MAX_NSTREAMS) >= m_expected);
  return m_expected;
}

void libxstream_event::enqueue(libxstream_stream& stream, bool reset)
{
  LIBXSTREAM_ASYNC_BEGIN(stream, m_slots, &m_expected, static_cast<libxstream_bool>(reset ? LIBXSTREAM_TRUE : LIBXSTREAM_FALSE))
  {
    libxstream_event::enqueue(thread(), *LIBXSTREAM_ASYNC_STREAM, ptr<slot_type,0>(), *ptr<size_t,1>(), val<bool,2>());
  }
  LIBXSTREAM_ASYNC_END(LIBXSTREAM_CALL_UNLOCK);
}

int libxstream_event::query(bool& occurred, libxstream_stream* stream) const
{
  int result = LIBXSTREAM_ERROR_NONE;

  LIBXSTREAM_ASYNC_BEGIN(stream, &result, &m_expected, m_slots, &occurred)
  {
    const size_t expected = *ptr<const size_t,1>();
    slot_type *const slots = ptr<slot_type,2>();
    bool occurred = true; // everythig "occurred" if nothing is expected

    if (LIBXSTREAM_ASYNC_STREAM) {
      *ptr<int,0>() = LIBXSTREAM_ASYNC_STREAM->reset();
    }

    for (size_t i = 0; i < expected; ++i) {
      slot_type& slot = slots[i];

      if (slot.match(LIBXSTREAM_ASYNC_STREAM) && 0 != slot.pending()) {
        libxstream_event::update(thread(), slot);
        occurred = occurred && 0 == slot.pending();
      }
    }

    *ptr<bool,3>() = occurred;
  }
  LIBXSTREAM_ASYNC_END(LIBXSTREAM_CALL_WAIT);

  return result;
}

int libxstream_event::wait(libxstream_stream* stream)
{
  int result = LIBXSTREAM_ERROR_NONE;

  LIBXSTREAM_ASYNC_BEGIN(stream, &result, &m_expected, m_slots)
  {
    size_t& expected = *ptr<size_t,1>();
    slot_type *const slots = ptr<slot_type,2>();
    size_t completed = 0;

    if (LIBXSTREAM_ASYNC_STREAM) {
      *ptr<int,0>() = LIBXSTREAM_ASYNC_STREAM->reset();
    }

    for (size_t i = 0; i < expected; ++i) {
      slot_type& slot = slots[i];
      const libxstream_signal pending_stream = slot.stream().pending(thread());
      const libxstream_signal pending_slot = slot.pending();

      if (slot.match(LIBXSTREAM_ASYNC_STREAM) && 0 != pending_stream && 0 != pending_slot) {
#if defined(LIBXSTREAM_EVENT_WAIT_OCCURRED)
        do { // spin/yield
          libxstream_event::update(thread(), slot);
          this_thread_yield();
        }
        while(0 != slot.pending());
#else
# if defined(LIBXSTREAM_EVENT_WAIT_PAST)
        const libxstream_signal signal = pending_slot;
# else
        const libxstream_signal signal = pending_stream;
# endif
# if defined(LIBXSTREAM_OFFLOAD) && defined(LIBXSTREAM_ASYNC) && (0 != (2*LIBXSTREAM_ASYNC+1)/2)
        if (0 <= slot.stream().device()) {
          LIBXSTREAM_ASYNC_DEVICE_UPDATE(slot.stream().device());
#         pragma offload_wait LIBXSTREAM_ASYNC_TARGET wait(signal)
        }
# endif
        if (signal == pending_stream) {
          slot.stream().pending(thread(), 0);
        }
#endif
        ++completed;
      }
    }

    LIBXSTREAM_ASSERT(completed <= expected);
    expected -= completed;
  }
  LIBXSTREAM_ASYNC_END(LIBXSTREAM_CALL_WAIT | LIBXSTREAM_CALL_UNLOCK);

  return result;
}
<|endoftext|>


<commit_before>#include <gmock/gmock.h>
#include "string_util.hpp"
#include "resourcemapper.hpp"
#include "gridmap.hpp"
#include "renderer.hpp"
#include <array>

class TestCoordinateSpace : public CoordinateSpace
{
public:
    TestCoordinateSpace(int w, int h)
    {
        mW = w;
        mH = h;
    }
    using CoordinateSpace::UpdateCamera;
};

TEST(CoordinateSpace, WorldToScreen_11)
{
    TestCoordinateSpace coords(640, 480);
    coords.mCameraPosition = { 0.0f, 0.0f };
    coords.mScreenSize = { 640.0f, 480.0f };
    coords.UpdateCamera();

    const glm::vec2 actual = coords.WorldToScreen({ 50.0f, 100.0f });
    ASSERT_EQ(glm::round((640.0f/2)+50.0f), glm::round(actual.x));
    ASSERT_EQ(glm::round((480.0f/2)+100.0f), glm::round(actual.y));
}

TEST(CoordinateSpace, ScreenToWorld_11)
{
    TestCoordinateSpace coords(640, 480);
    coords.mCameraPosition = { 0.0f, 0.0f };
    coords.mScreenSize = { 640.0f, 480.0f };
    coords.UpdateCamera();

    const glm::vec2 actual = coords.ScreenToWorld({ 50.0f, 100.0f });
    ASSERT_EQ(glm::round(50.0f - 640/2), glm::round(actual.x));
    ASSERT_EQ(glm::round(100.0f - 480/2), glm::round(actual.y));
}

/*
TEST(CoordinateSpace, WorldToScreen_12)
{
    TestCoordinateSpace coords(640*2, 480*2);
    coords.mCameraPosition = { 0.0f, 0.0f };
    coords.mScreenSize = { 640.0f, 480.0f };
    coords.UpdateCamera();

    const glm::vec2 actual = coords.WorldToScreen({ 50.0f, 100.0f });
    ASSERT_EQ(glm::round(50.0f*2), glm::round(actual.x));
    ASSERT_EQ(glm::round(100.0f*2), glm::round(actual.y));
}

TEST(CoordinateSpace, ScreenToWorld_12)
{
    TestCoordinateSpace coords(640 * 2, 480 * 2);
    coords.mCameraPosition = { 0.0f, 0.0f };
    coords.mScreenSize = { 640.0f, 480.0f };
    coords.UpdateCamera();

    const glm::vec2 actual = coords.ScreenToWorld({ 50.0f * 2, 100.0f * 2 });
    ASSERT_EQ(glm::round(50.0f), glm::round(actual.x));
    ASSERT_EQ(glm::round(100.0f), glm::round(actual.y));
}

TEST(CoordinateSpace, WorldToScreen_11_offset)
{
    TestCoordinateSpace coords(640, 480);
    coords.mCameraPosition = { 10.0f, 10.0f };
    coords.mScreenSize = { 640.0f, 480.0f };
    coords.UpdateCamera();

    const glm::vec2 actual = coords.WorldToScreen({ 50.0f, 100.0f });
    ASSERT_EQ(glm::round(50.0f + 10.0f), glm::round(actual.x));
    ASSERT_EQ(glm::round(100.0f + 10.0f), glm::round(actual.y));
}

// TODO: Screen

TEST(CoordinateSpace, WorldToScreen_12_offset)
{
    TestCoordinateSpace coords(640*2, 480 * 2);
    coords.mCameraPosition = { 10.0f, 10.0f };
    coords.mScreenSize = { 640.0f, 480.0f };
    coords.UpdateCamera();

    const glm::vec2 actual = coords.WorldToScreen({ 50.0f, 100.0f });
    ASSERT_EQ(glm::round((50.0f + 10.0f)*2), glm::round(actual.x));
    ASSERT_EQ(glm::round((100.0f + 10.0f)*2), glm::round(actual.y));
}

// TODO: Screen
*/

TEST(CollisionLines, IsPointInCircle)
{
    ASSERT_TRUE(Physics::IsPointInCircle(glm::vec2(0.0f, 0.0f), 5.0f, glm::vec2(0.0f, 0.0f)));
    ASSERT_FALSE(Physics::IsPointInCircle(glm::vec2(0.0f, 0.0f), 5.0f, glm::vec2(0.0f, 7.0f)));
    ASSERT_TRUE(Physics::IsPointInCircle(glm::vec2(0.0f, 0.0f), 5.0f, glm::vec2(-3.0f, 3.0f)));
}

TEST(CollisionLines, IsPointInTriangle)
{
    ASSERT_TRUE(Physics::IsPointInTriangle(glm::vec2(0.0f, 0.0f), glm::vec2(100.0f, 0.0f), glm::vec2(0.0f, 50.0f), glm::vec2(30.0f, 10.0f)));
    ASSERT_FALSE(Physics::IsPointInTriangle(glm::vec2(0.0f, 0.0f), glm::vec2(0.0f, 100.0f), glm::vec2(50.0f, 100.0f), glm::vec2(1000.0f, 1000.0f)));
}

TEST(CollisionLines, PointInLineSegmentRect)
{
    const f32 kWidth = 2.0f;

    ASSERT_TRUE(Physics::IsPointInThickLine(glm::vec2(0.0f, 0.0f), glm::vec2(20.0f, 0.0f), glm::vec2(10.0f, 0.0f), kWidth));
    ASSERT_FALSE(Physics::IsPointInThickLine(glm::vec2(0.0f, 0.0f), glm::vec2(20.0f, 0.0f), glm::vec2(10.0f, 10.0f), kWidth));

    ASSERT_TRUE(Physics::IsPointInThickLine(glm::vec2(0.0f, 0.0f), glm::vec2(0.0f, 200.0f), glm::vec2(0.0f, 50.0f), kWidth));
    ASSERT_FALSE(Physics::IsPointInThickLine(glm::vec2(0.0f, 0.0f), glm::vec2(0.0f, 200.0f), glm::vec2(10.0f, 50.0f), kWidth));

    ASSERT_TRUE(Physics::IsPointInThickLine(glm::vec2(0.0f, 0.0f), glm::vec2(10.0f, 10.0f), glm::vec2(5.0f, 5.0f), kWidth));
    ASSERT_FALSE(Physics::IsPointInThickLine(glm::vec2(0.0f, 0.0f), glm::vec2(10.0f, 10.0f), glm::vec2(0.0f, 5.0f), kWidth));
}

TEST(Collision, NoLines)
{
    Physics::raycast_collision hitPoint;
    CollisionLines lines;
    ASSERT_FALSE(CollisionLine::RayCast<1>(lines, { 0, 0 }, { 10, 10 }, { CollisionLine::eFloor }, &hitPoint));
}

TEST(Collision, NoLinesMultiInput)
{
    Physics::raycast_collision hitPoint;
    CollisionLines lines;
    ASSERT_FALSE(CollisionLine::RayCast<2>(lines, { 0, 0 }, { 10, 10 }, { CollisionLine::eFloor, CollisionLine::eBulletWall }, &hitPoint));
}

// TODO FIX ME
TEST(Collision, DISABLED_LineWithinLine)
{
    Physics::raycast_collision hitPoint;
    CollisionLines lines;
    lines.emplace_back(std::make_unique<CollisionLine>(glm::vec2 { 0, 0 }, glm::vec2{ 10, 0 }, CollisionLine::eFloor));

    ASSERT_TRUE(CollisionLine::RayCast<1>(lines, { 5, 0 }, { 9, 0 }, { CollisionLine::eFloor }, &hitPoint));
    ASSERT_EQ(hitPoint.intersection.x, 0);
    ASSERT_EQ(hitPoint.intersection.y, 0);
}

// If we collide with 2 lines make sure the nearest collision point wins
TEST(Collision, NearestHitPointWins)
{
    Physics::raycast_collision hitPoint;
    CollisionLines lines;
    lines.emplace_back(std::make_unique<CollisionLine>(glm::vec2{ 1949, 1240 }, glm::vec2{ 2250, 1240 }, CollisionLine::eFloor));
    lines.emplace_back(std::make_unique<CollisionLine>(glm::vec2{ 1751, 1140 }, glm::vec2{ 1975, 1140 }, CollisionLine::eFloor));

    ASSERT_TRUE(CollisionLine::RayCast<1>(lines, { 1957, 1090 }, { 1957, 1590 }, { CollisionLine::eFloor }, &hitPoint));
    ASSERT_EQ(hitPoint.intersection.x, 1957);
    ASSERT_EQ(hitPoint.intersection.y, 1140);
}
<commit_msg>add other tests<commit_after>#include <gmock/gmock.h>
#include "string_util.hpp"
#include "resourcemapper.hpp"
#include "gridmap.hpp"
#include "renderer.hpp"
#include <array>

class TestCoordinateSpace : public CoordinateSpace
{
public:
    TestCoordinateSpace(int w, int h)
    {
        mW = w;
        mH = h;
    }
    using CoordinateSpace::UpdateCamera;
};

TEST(CoordinateSpace, WorldToScreen_11)
{
    TestCoordinateSpace coords(640, 480);
    coords.mCameraPosition = { 0.0f, 0.0f };
    coords.mScreenSize = { 640.0f, 480.0f };
    coords.UpdateCamera();

    const glm::vec2 actual = coords.WorldToScreen({ 50.0f, 100.0f });
    ASSERT_EQ(glm::round((640.0f/2)+50.0f), glm::round(actual.x));
    ASSERT_EQ(glm::round((480.0f/2)+100.0f), glm::round(actual.y));
}

TEST(CoordinateSpace, ScreenToWorld_11)
{
    TestCoordinateSpace coords(640, 480);
    coords.mCameraPosition = { 0.0f, 0.0f };
    coords.mScreenSize = { 640.0f, 480.0f };
    coords.UpdateCamera();

    const glm::vec2 actual = coords.ScreenToWorld({ 50.0f, 100.0f });
    ASSERT_EQ(glm::round(50.0f - 640/2), glm::round(actual.x));
    ASSERT_EQ(glm::round(100.0f - 480/2), glm::round(actual.y));
}

TEST(CoordinateSpace, WorldToScreen_12)
{
    TestCoordinateSpace coords(640*2, 480*2);
    coords.mCameraPosition = { 0.0f, 0.0f };
    coords.mScreenSize = { 640.0f, 480.0f };
    coords.UpdateCamera();

    const glm::vec2 actual = coords.WorldToScreen({ 50.0f, 100.0f });
    ASSERT_EQ(glm::round(640.0f + 50.0f * 2), glm::round(actual.x));
    ASSERT_EQ(glm::round(480.0f + 100.0f * 2), glm::round(actual.y));
}

TEST(CoordinateSpace, ScreenToWorld_12)
{
    TestCoordinateSpace coords(640 * 2, 480 * 2);
    coords.mCameraPosition = { 0.0f, 0.0f };
    coords.mScreenSize = { 640.0f, 480.0f };
    coords.UpdateCamera();

    const glm::vec2 actual = coords.ScreenToWorld({ 640.0f + 50.0f * 2, 480.0f + 100.0f * 2 });
    ASSERT_EQ(glm::round(50.0f), glm::round(actual.x));
    ASSERT_EQ(glm::round(100.0f), glm::round(actual.y));
}

TEST(CoordinateSpace, WorldToScreen_11_offset)
{
    TestCoordinateSpace coords(640, 480);
    coords.mCameraPosition = { 10.0f, 10.0f };
    coords.mScreenSize = { 640.0f, 480.0f };
    coords.UpdateCamera();

    const glm::vec2 actual = coords.WorldToScreen({ 50.0f, 100.0f });
    ASSERT_EQ(glm::round((640.0f/2) + 50.0f - 10.0f), glm::round(actual.x));
    ASSERT_EQ(glm::round((480.0f/2) + 100.0f - 10.0f), glm::round(actual.y));
}

TEST(CoordinateSpace, ScreenToWorld_11_offset)
{
    TestCoordinateSpace coords(640, 480);
    coords.mCameraPosition = { 10.0f, 10.0f };
    coords.mScreenSize = { 640.0f, 480.0f };
    coords.UpdateCamera();

    const glm::vec2 actual = coords.ScreenToWorld({ (640.0f / 2) + 50.0f - 10.0f, (480.0f / 2) + 100.0f - 10.0f });
    ASSERT_EQ(glm::round(50.0f), glm::round(actual.x));
    ASSERT_EQ(glm::round(100.0f), glm::round(actual.y));
}

TEST(CoordinateSpace, WorldToScreen_12_offset)
{
    TestCoordinateSpace coords(640*2, 480 * 2);
    coords.mCameraPosition = { 10.0f, 10.0f };
    coords.mScreenSize = { 640.0f, 480.0f };
    coords.UpdateCamera();

    const glm::vec2 actual = coords.WorldToScreen({ 50.0f, 100.0f });
    ASSERT_EQ(glm::round((640.0f) + (50.0f - 10.0f)*2), glm::round(actual.x));
    ASSERT_EQ(glm::round((480.0f) + (100.0f - 10.0f)*2), glm::round(actual.y));
}

TEST(CoordinateSpace, ScreenToWorld_12_offset)
{
    TestCoordinateSpace coords(640 * 2, 480 * 2);
    coords.mCameraPosition = { 10.0f, 10.0f };
    coords.mScreenSize = { 640.0f, 480.0f };
    coords.UpdateCamera();

    const glm::vec2 actual = coords.ScreenToWorld({ (640.0f) + (50.0f - 10.0f) * 2, (480.0f) + (100.0f - 10.0f) * 2 });
    ASSERT_EQ(glm::round(50.0f), glm::round(actual.x));
    ASSERT_EQ(glm::round(100.0f), glm::round(actual.y));
}

TEST(CollisionLines, IsPointInCircle)
{
    ASSERT_TRUE(Physics::IsPointInCircle(glm::vec2(0.0f, 0.0f), 5.0f, glm::vec2(0.0f, 0.0f)));
    ASSERT_FALSE(Physics::IsPointInCircle(glm::vec2(0.0f, 0.0f), 5.0f, glm::vec2(0.0f, 7.0f)));
    ASSERT_TRUE(Physics::IsPointInCircle(glm::vec2(0.0f, 0.0f), 5.0f, glm::vec2(-3.0f, 3.0f)));
}

TEST(CollisionLines, IsPointInTriangle)
{
    ASSERT_TRUE(Physics::IsPointInTriangle(glm::vec2(0.0f, 0.0f), glm::vec2(100.0f, 0.0f), glm::vec2(0.0f, 50.0f), glm::vec2(30.0f, 10.0f)));
    ASSERT_FALSE(Physics::IsPointInTriangle(glm::vec2(0.0f, 0.0f), glm::vec2(0.0f, 100.0f), glm::vec2(50.0f, 100.0f), glm::vec2(1000.0f, 1000.0f)));
}

TEST(CollisionLines, PointInLineSegmentRect)
{
    const f32 kWidth = 2.0f;

    ASSERT_TRUE(Physics::IsPointInThickLine(glm::vec2(0.0f, 0.0f), glm::vec2(20.0f, 0.0f), glm::vec2(10.0f, 0.0f), kWidth));
    ASSERT_FALSE(Physics::IsPointInThickLine(glm::vec2(0.0f, 0.0f), glm::vec2(20.0f, 0.0f), glm::vec2(10.0f, 10.0f), kWidth));

    ASSERT_TRUE(Physics::IsPointInThickLine(glm::vec2(0.0f, 0.0f), glm::vec2(0.0f, 200.0f), glm::vec2(0.0f, 50.0f), kWidth));
    ASSERT_FALSE(Physics::IsPointInThickLine(glm::vec2(0.0f, 0.0f), glm::vec2(0.0f, 200.0f), glm::vec2(10.0f, 50.0f), kWidth));

    ASSERT_TRUE(Physics::IsPointInThickLine(glm::vec2(0.0f, 0.0f), glm::vec2(10.0f, 10.0f), glm::vec2(5.0f, 5.0f), kWidth));
    ASSERT_FALSE(Physics::IsPointInThickLine(glm::vec2(0.0f, 0.0f), glm::vec2(10.0f, 10.0f), glm::vec2(0.0f, 5.0f), kWidth));
}

TEST(Collision, NoLines)
{
    Physics::raycast_collision hitPoint;
    CollisionLines lines;
    ASSERT_FALSE(CollisionLine::RayCast<1>(lines, { 0, 0 }, { 10, 10 }, { CollisionLine::eFloor }, &hitPoint));
}

TEST(Collision, NoLinesMultiInput)
{
    Physics::raycast_collision hitPoint;
    CollisionLines lines;
    ASSERT_FALSE(CollisionLine::RayCast<2>(lines, { 0, 0 }, { 10, 10 }, { CollisionLine::eFloor, CollisionLine::eBulletWall }, &hitPoint));
}

// TODO FIX ME
TEST(Collision, DISABLED_LineWithinLine)
{
    Physics::raycast_collision hitPoint;
    CollisionLines lines;
    lines.emplace_back(std::make_unique<CollisionLine>(glm::vec2 { 0, 0 }, glm::vec2{ 10, 0 }, CollisionLine::eFloor));

    ASSERT_TRUE(CollisionLine::RayCast<1>(lines, { 5, 0 }, { 9, 0 }, { CollisionLine::eFloor }, &hitPoint));
    ASSERT_EQ(hitPoint.intersection.x, 0);
    ASSERT_EQ(hitPoint.intersection.y, 0);
}

// If we collide with 2 lines make sure the nearest collision point wins
TEST(Collision, NearestHitPointWins)
{
    Physics::raycast_collision hitPoint;
    CollisionLines lines;
    lines.emplace_back(std::make_unique<CollisionLine>(glm::vec2{ 1949, 1240 }, glm::vec2{ 2250, 1240 }, CollisionLine::eFloor));
    lines.emplace_back(std::make_unique<CollisionLine>(glm::vec2{ 1751, 1140 }, glm::vec2{ 1975, 1140 }, CollisionLine::eFloor));

    ASSERT_TRUE(CollisionLine::RayCast<1>(lines, { 1957, 1090 }, { 1957, 1590 }, { CollisionLine::eFloor }, &hitPoint));
    ASSERT_EQ(hitPoint.intersection.x, 1957);
    ASSERT_EQ(hitPoint.intersection.y, 1140);
}
<|endoftext|>


<commit_before>//===- DeadMachineInstructionElim.cpp - Remove dead machine instructions --===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is an extremely simple MachineInstr-level dead-code-elimination pass.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/Passes.h"
#include "llvm/Pass.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
using namespace llvm;

namespace {
  class VISIBILITY_HIDDEN DeadMachineInstructionElim :
        public MachineFunctionPass {
    virtual bool runOnMachineFunction(MachineFunction &MF);

    const TargetRegisterInfo *TRI;
    const MachineRegisterInfo *MRI;
    const TargetInstrInfo *TII;
    BitVector LivePhysRegs;

  public:
    static char ID; // Pass identification, replacement for typeid
    DeadMachineInstructionElim() : MachineFunctionPass(&ID) {}

  private:
    bool isDead(MachineInstr *MI) const;
  };
}
char DeadMachineInstructionElim::ID = 0;

static RegisterPass<DeadMachineInstructionElim>
Y("dead-mi-elimination",
  "Remove dead machine instructions");

FunctionPass *llvm::createDeadMachineInstructionElimPass() {
  return new DeadMachineInstructionElim();
}

bool DeadMachineInstructionElim::isDead(MachineInstr *MI) const {
  // Don't delete instructions with side effects.
  bool SawStore = false;
  if (!MI->isSafeToMove(TII, SawStore))
    return false;

  // Examine each operand.
  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
    const MachineOperand &MO = MI->getOperand(i);
    if (MO.isReg() && MO.isDef()) {
      unsigned Reg = MO.getReg();
      if (TargetRegisterInfo::isPhysicalRegister(Reg) ?
          LivePhysRegs[Reg] : !MRI->use_empty(Reg)) {
        // This def has a use. Don't delete the instruction!
        return false;
      }
    }
  }

  // If there are no defs with uses, the instruction is dead.
  return true;
}

bool DeadMachineInstructionElim::runOnMachineFunction(MachineFunction &MF) {
  bool AnyChanges = false;
  MRI = &MF.getRegInfo();
  TRI = MF.getTarget().getRegisterInfo();
  TII = MF.getTarget().getInstrInfo();

  // Compute a bitvector to represent all non-allocatable physregs.
  BitVector NonAllocatableRegs = TRI->getAllocatableSet(MF);
  NonAllocatableRegs.flip();

  // Loop over all instructions in all blocks, from bottom to top, so that it's
  // more likely that chains of dependent but ultimately dead instructions will
  // be cleaned up.
  for (MachineFunction::reverse_iterator I = MF.rbegin(), E = MF.rend();
       I != E; ++I) {
    MachineBasicBlock *MBB = &*I;

    // Start out assuming that all non-allocatable registers are live
    // out of this block.
    LivePhysRegs = NonAllocatableRegs;

    // Also add any explicit live-out physregs for this block.
    if (!MBB->empty() && MBB->back().getDesc().isReturn())
      for (MachineRegisterInfo::liveout_iterator LOI = MRI->liveout_begin(),
           LOE = MRI->liveout_end(); LOI != LOE; ++LOI) {
        unsigned Reg = *LOI;
        if (TargetRegisterInfo::isPhysicalRegister(Reg))
          LivePhysRegs.set(Reg);
      }

    // Now scan the instructions and delete dead ones, tracking physreg
    // liveness as we go.
    for (MachineBasicBlock::reverse_iterator MII = MBB->rbegin(),
         MIE = MBB->rend(); MII != MIE; ) {
      MachineInstr *MI = &*MII;

      // If the instruction is dead, delete it!
      if (isDead(MI)) {
        DOUT << "DeadMachineInstructionElim: DELETING: " << *MI;
        AnyChanges = true;
        MI->eraseFromParent();
        MIE = MBB->rend();
        // MII is now pointing to the next instruction to process,
        // so don't increment it.
        continue;
      }

      // Record the physreg defs.
      for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
        const MachineOperand &MO = MI->getOperand(i);
        if (MO.isReg() && MO.isDef()) {
          unsigned Reg = MO.getReg();
          if (Reg != 0 && TargetRegisterInfo::isPhysicalRegister(Reg)) {
            LivePhysRegs.reset(Reg);
            // Check the subreg set, not the alias set, because a def
            // of a super-register may still be partially live after
            // this def.
            for (const unsigned *AliasSet = TRI->getSubRegisters(Reg);
                 *AliasSet; ++AliasSet)
              LivePhysRegs.reset(*AliasSet);
          }
        }
      }
      // Record the physreg uses, after the defs, in case a physreg is
      // both defined and used in the same instruction.
      for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
        const MachineOperand &MO = MI->getOperand(i);
        if (MO.isReg() && MO.isUse()) {
          unsigned Reg = MO.getReg();
          if (Reg != 0 && TargetRegisterInfo::isPhysicalRegister(Reg)) {
            LivePhysRegs.set(Reg);
            for (const unsigned *AliasSet = TRI->getAliasSet(Reg);
                 *AliasSet; ++AliasSet)
              LivePhysRegs.set(*AliasSet);
          }
        }
      }

      // We didn't delete the current instruction, so increment MII to
      // the next one.
      ++MII;
    }
  }

  LivePhysRegs.clear();
  return AnyChanges;
}
<commit_msg>Rename AliasSet to SubRegs, to reflect changes in the surrounding code.<commit_after>//===- DeadMachineInstructionElim.cpp - Remove dead machine instructions --===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is an extremely simple MachineInstr-level dead-code-elimination pass.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/Passes.h"
#include "llvm/Pass.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
using namespace llvm;

namespace {
  class VISIBILITY_HIDDEN DeadMachineInstructionElim :
        public MachineFunctionPass {
    virtual bool runOnMachineFunction(MachineFunction &MF);

    const TargetRegisterInfo *TRI;
    const MachineRegisterInfo *MRI;
    const TargetInstrInfo *TII;
    BitVector LivePhysRegs;

  public:
    static char ID; // Pass identification, replacement for typeid
    DeadMachineInstructionElim() : MachineFunctionPass(&ID) {}

  private:
    bool isDead(MachineInstr *MI) const;
  };
}
char DeadMachineInstructionElim::ID = 0;

static RegisterPass<DeadMachineInstructionElim>
Y("dead-mi-elimination",
  "Remove dead machine instructions");

FunctionPass *llvm::createDeadMachineInstructionElimPass() {
  return new DeadMachineInstructionElim();
}

bool DeadMachineInstructionElim::isDead(MachineInstr *MI) const {
  // Don't delete instructions with side effects.
  bool SawStore = false;
  if (!MI->isSafeToMove(TII, SawStore))
    return false;

  // Examine each operand.
  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
    const MachineOperand &MO = MI->getOperand(i);
    if (MO.isReg() && MO.isDef()) {
      unsigned Reg = MO.getReg();
      if (TargetRegisterInfo::isPhysicalRegister(Reg) ?
          LivePhysRegs[Reg] : !MRI->use_empty(Reg)) {
        // This def has a use. Don't delete the instruction!
        return false;
      }
    }
  }

  // If there are no defs with uses, the instruction is dead.
  return true;
}

bool DeadMachineInstructionElim::runOnMachineFunction(MachineFunction &MF) {
  bool AnyChanges = false;
  MRI = &MF.getRegInfo();
  TRI = MF.getTarget().getRegisterInfo();
  TII = MF.getTarget().getInstrInfo();

  // Compute a bitvector to represent all non-allocatable physregs.
  BitVector NonAllocatableRegs = TRI->getAllocatableSet(MF);
  NonAllocatableRegs.flip();

  // Loop over all instructions in all blocks, from bottom to top, so that it's
  // more likely that chains of dependent but ultimately dead instructions will
  // be cleaned up.
  for (MachineFunction::reverse_iterator I = MF.rbegin(), E = MF.rend();
       I != E; ++I) {
    MachineBasicBlock *MBB = &*I;

    // Start out assuming that all non-allocatable registers are live
    // out of this block.
    LivePhysRegs = NonAllocatableRegs;

    // Also add any explicit live-out physregs for this block.
    if (!MBB->empty() && MBB->back().getDesc().isReturn())
      for (MachineRegisterInfo::liveout_iterator LOI = MRI->liveout_begin(),
           LOE = MRI->liveout_end(); LOI != LOE; ++LOI) {
        unsigned Reg = *LOI;
        if (TargetRegisterInfo::isPhysicalRegister(Reg))
          LivePhysRegs.set(Reg);
      }

    // Now scan the instructions and delete dead ones, tracking physreg
    // liveness as we go.
    for (MachineBasicBlock::reverse_iterator MII = MBB->rbegin(),
         MIE = MBB->rend(); MII != MIE; ) {
      MachineInstr *MI = &*MII;

      // If the instruction is dead, delete it!
      if (isDead(MI)) {
        DOUT << "DeadMachineInstructionElim: DELETING: " << *MI;
        AnyChanges = true;
        MI->eraseFromParent();
        MIE = MBB->rend();
        // MII is now pointing to the next instruction to process,
        // so don't increment it.
        continue;
      }

      // Record the physreg defs.
      for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
        const MachineOperand &MO = MI->getOperand(i);
        if (MO.isReg() && MO.isDef()) {
          unsigned Reg = MO.getReg();
          if (Reg != 0 && TargetRegisterInfo::isPhysicalRegister(Reg)) {
            LivePhysRegs.reset(Reg);
            // Check the subreg set, not the alias set, because a def
            // of a super-register may still be partially live after
            // this def.
            for (const unsigned *SubRegs = TRI->getSubRegisters(Reg);
                 *SubRegs; ++SubRegs)
              LivePhysRegs.reset(*SubRegs);
          }
        }
      }
      // Record the physreg uses, after the defs, in case a physreg is
      // both defined and used in the same instruction.
      for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
        const MachineOperand &MO = MI->getOperand(i);
        if (MO.isReg() && MO.isUse()) {
          unsigned Reg = MO.getReg();
          if (Reg != 0 && TargetRegisterInfo::isPhysicalRegister(Reg)) {
            LivePhysRegs.set(Reg);
            for (const unsigned *AliasSet = TRI->getAliasSet(Reg);
                 *AliasSet; ++AliasSet)
              LivePhysRegs.set(*AliasSet);
          }
        }
      }

      // We didn't delete the current instruction, so increment MII to
      // the next one.
      ++MII;
    }
  }

  LivePhysRegs.clear();
  return AnyChanges;
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include <iostream>
#include <chrono>
#include <random>

#include "etl/etl.hpp"

#define CPM_NO_RANDOMIZATION            //Randomly initialize only once
#define CPM_AUTO_STEPS                  //Enable steps estimation system
#define CPM_STEP_ESTIMATION_MIN 0.05    //Run during 0.05 seconds for estimating steps
#define CPM_RUNTIME_TARGET 0.9          //Run each test during 0.9 seconds

#include "cpm/cpm.hpp"

#ifdef ETL_VECTORIZE_IMPL
#ifdef __SSE3__
#define TEST_SSE
#endif
#ifdef __AVX__
#define TEST_AVX
#endif
#endif

#ifdef ETL_MKL_MODE
#define TEST_MKL
#endif

#ifdef ETL_CUBLAS_MODE
#define TEST_CUBLAS
#endif

#ifdef ETL_CUFFT_MODE
#define TEST_CUFFT
#endif

#ifdef ETL_BLAS_MODE
#define TEST_BLAS
#endif

#ifdef ETL_BENCH_STRASSEN
#define TEST_STRASSEN
#endif

#ifdef ETL_BENCH_MMUL_CONV
#define TEST_MMUL_CONV
#endif

using smat_cm = etl::dyn_matrix_cm<float>;
using dmat_cm = etl::dyn_matrix_cm<double>;
using cmat_cm = etl::dyn_matrix_cm<std::complex<float>>;
using zmat_cm = etl::dyn_matrix_cm<std::complex<double>>;

using dvec = etl::dyn_vector<double>;
using dmat = etl::dyn_matrix<double>;
using dmat2 = etl::dyn_matrix<double, 2>;
using dmat3 = etl::dyn_matrix<double, 3>;
using dmat4 = etl::dyn_matrix<double, 4>;

using svec = etl::dyn_vector<float>;
using smat = etl::dyn_matrix<float>;

using cvec = etl::dyn_vector<std::complex<float>>;
using cmat = etl::dyn_matrix<std::complex<float>>;

using zvec = etl::dyn_vector<std::complex<double>>;
using zmat = etl::dyn_matrix<std::complex<double>>;

using mat_policy = VALUES_POLICY(10, 25, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 2000,3000,4000);
using mat_policy_2d = NARY_POLICY(mat_policy, mat_policy);

using conv_1d_large_policy = NARY_POLICY(VALUES_POLICY(1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000), VALUES_POLICY(500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000));
using conv_2d_large_policy = NARY_POLICY(VALUES_POLICY(100, 105, 110, 115, 120, 125, 130, 135, 140), VALUES_POLICY(50, 50, 55, 55, 60, 60, 65, 65, 70));

using fft_1d_policy = VALUES_POLICY(10, 100, 1000, 10000, 100000, 500000);
using fft_1d_policy_2 = VALUES_POLICY(16, 64, 256, 1024, 16384, 131072, 1048576, 2097152);
using fft_1d_many_policy = VALUES_POLICY(10, 50, 100, 500, 1000, 5000, 10000);

using fft_2d_policy = NARY_POLICY(
    VALUES_POLICY(8, 16, 32, 64, 128, 256, 512, 1024, 2048),
    VALUES_POLICY(8, 16, 32, 64, 128, 256, 512, 1024, 2048));

using sigmoid_policy = VALUES_POLICY(250, 500, 750, 1000, 1250, 1500, 1750, 2000);

using small_square_policy = NARY_POLICY(VALUES_POLICY(50, 100, 150, 200, 250, 300, 350, 400, 450, 500), VALUES_POLICY(50, 100, 150, 200, 250, 300, 350, 400, 450, 500));
using square_policy = NARY_POLICY(VALUES_POLICY(50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000), VALUES_POLICY(50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000));

using gemv_policy = NARY_POLICY(
    VALUES_POLICY(250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000),
    VALUES_POLICY(250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000));

using trans_sub_policy = VALUES_POLICY(100, 200, 300, 400, 500, 600, 700, 800, 900, 1000);
using trans_policy = NARY_POLICY(
    VALUES_POLICY(100, 100, 200, 200, 300, 300, 400, 400, 500, 500, 600, 600, 700, 700, 800, 800, 900, 900, 1000, 1000),
    VALUES_POLICY(100, 200, 200, 300, 300, 400, 400, 500, 500, 600, 600, 700, 700, 800, 800, 900, 900, 1000, 1000, 1100));

#ifdef TEST_SSE
#define SSE_SECTION_FUNCTOR(name, ...) , CPM_SECTION_FUNCTOR(name, __VA_ARGS__)
#else
#define SSE_SECTION_FUNCTOR(name, ...)
#endif

#ifdef TEST_AVX
#define AVX_SECTION_FUNCTOR(name, ...) , CPM_SECTION_FUNCTOR(name, __VA_ARGS__)
#else
#define AVX_SECTION_FUNCTOR(name, ...)
#endif

#ifdef TEST_MKL
#define MKL_SECTION_FUNCTOR(name, ...) , CPM_SECTION_FUNCTOR(name, __VA_ARGS__)
#else
#define MKL_SECTION_FUNCTOR(name, ...)
#endif

#ifdef TEST_BLAS
#define BLAS_SECTION_FUNCTOR(name, ...) , CPM_SECTION_FUNCTOR(name, __VA_ARGS__)
#else
#define BLAS_SECTION_FUNCTOR(name, ...)
#endif

#ifdef TEST_CUBLAS
#define CUBLAS_SECTION_FUNCTOR(name, ...) , CPM_SECTION_FUNCTOR(name, __VA_ARGS__)
#else
#define CUBLAS_SECTION_FUNCTOR(name, ...)
#endif

#ifdef TEST_CUFFT
#define CUFFT_SECTION_FUNCTOR(name, ...) , CPM_SECTION_FUNCTOR(name, __VA_ARGS__)
#else
#define CUFFT_SECTION_FUNCTOR(name, ...)
#endif

#ifdef TEST_MMUL_CONV
#define MC_SECTION_FUNCTOR(name, ...) , CPM_SECTION_FUNCTOR(name, __VA_ARGS__)
#else
#define MC_SECTION_FUNCTOR(name, ...)
#endif
<commit_msg>Save time on auto steps<commit_after>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

#include <iostream>
#include <chrono>
#include <random>

#include "etl/etl.hpp"

#define CPM_NO_RANDOMIZATION            //Randomly initialize only once
#define CPM_AUTO_STEPS                  //Enable steps estimation system
#define CPM_STEP_ESTIMATION_MIN 0.025   //Run during 0.025 seconds for estimating steps
#define CPM_RUNTIME_TARGET 0.9          //Run each test during 0.9 seconds

#include "cpm/cpm.hpp"

#ifdef ETL_VECTORIZE_IMPL
#ifdef __SSE3__
#define TEST_SSE
#endif
#ifdef __AVX__
#define TEST_AVX
#endif
#endif

#ifdef ETL_MKL_MODE
#define TEST_MKL
#endif

#ifdef ETL_CUBLAS_MODE
#define TEST_CUBLAS
#endif

#ifdef ETL_CUFFT_MODE
#define TEST_CUFFT
#endif

#ifdef ETL_BLAS_MODE
#define TEST_BLAS
#endif

#ifdef ETL_BENCH_STRASSEN
#define TEST_STRASSEN
#endif

#ifdef ETL_BENCH_MMUL_CONV
#define TEST_MMUL_CONV
#endif

using smat_cm = etl::dyn_matrix_cm<float>;
using dmat_cm = etl::dyn_matrix_cm<double>;
using cmat_cm = etl::dyn_matrix_cm<std::complex<float>>;
using zmat_cm = etl::dyn_matrix_cm<std::complex<double>>;

using dvec = etl::dyn_vector<double>;
using dmat = etl::dyn_matrix<double>;
using dmat2 = etl::dyn_matrix<double, 2>;
using dmat3 = etl::dyn_matrix<double, 3>;
using dmat4 = etl::dyn_matrix<double, 4>;

using svec = etl::dyn_vector<float>;
using smat = etl::dyn_matrix<float>;

using cvec = etl::dyn_vector<std::complex<float>>;
using cmat = etl::dyn_matrix<std::complex<float>>;

using zvec = etl::dyn_vector<std::complex<double>>;
using zmat = etl::dyn_matrix<std::complex<double>>;

using mat_policy = VALUES_POLICY(10, 25, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 2000,3000,4000);
using mat_policy_2d = NARY_POLICY(mat_policy, mat_policy);

using conv_1d_large_policy = NARY_POLICY(VALUES_POLICY(1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000), VALUES_POLICY(500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000));
using conv_2d_large_policy = NARY_POLICY(VALUES_POLICY(100, 105, 110, 115, 120, 125, 130, 135, 140), VALUES_POLICY(50, 50, 55, 55, 60, 60, 65, 65, 70));

using fft_1d_policy = VALUES_POLICY(10, 100, 1000, 10000, 100000, 500000);
using fft_1d_policy_2 = VALUES_POLICY(16, 64, 256, 1024, 16384, 131072, 1048576, 2097152);
using fft_1d_many_policy = VALUES_POLICY(10, 50, 100, 500, 1000, 5000, 10000);

using fft_2d_policy = NARY_POLICY(
    VALUES_POLICY(8, 16, 32, 64, 128, 256, 512, 1024, 2048),
    VALUES_POLICY(8, 16, 32, 64, 128, 256, 512, 1024, 2048));

using sigmoid_policy = VALUES_POLICY(250, 500, 750, 1000, 1250, 1500, 1750, 2000);

using small_square_policy = NARY_POLICY(VALUES_POLICY(50, 100, 150, 200, 250, 300, 350, 400, 450, 500), VALUES_POLICY(50, 100, 150, 200, 250, 300, 350, 400, 450, 500));
using square_policy = NARY_POLICY(VALUES_POLICY(50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000), VALUES_POLICY(50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000));

using gemv_policy = NARY_POLICY(
    VALUES_POLICY(250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000),
    VALUES_POLICY(250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000));

using trans_sub_policy = VALUES_POLICY(100, 200, 300, 400, 500, 600, 700, 800, 900, 1000);
using trans_policy = NARY_POLICY(
    VALUES_POLICY(100, 100, 200, 200, 300, 300, 400, 400, 500, 500, 600, 600, 700, 700, 800, 800, 900, 900, 1000, 1000),
    VALUES_POLICY(100, 200, 200, 300, 300, 400, 400, 500, 500, 600, 600, 700, 700, 800, 800, 900, 900, 1000, 1000, 1100));

#ifdef TEST_SSE
#define SSE_SECTION_FUNCTOR(name, ...) , CPM_SECTION_FUNCTOR(name, __VA_ARGS__)
#else
#define SSE_SECTION_FUNCTOR(name, ...)
#endif

#ifdef TEST_AVX
#define AVX_SECTION_FUNCTOR(name, ...) , CPM_SECTION_FUNCTOR(name, __VA_ARGS__)
#else
#define AVX_SECTION_FUNCTOR(name, ...)
#endif

#ifdef TEST_MKL
#define MKL_SECTION_FUNCTOR(name, ...) , CPM_SECTION_FUNCTOR(name, __VA_ARGS__)
#else
#define MKL_SECTION_FUNCTOR(name, ...)
#endif

#ifdef TEST_BLAS
#define BLAS_SECTION_FUNCTOR(name, ...) , CPM_SECTION_FUNCTOR(name, __VA_ARGS__)
#else
#define BLAS_SECTION_FUNCTOR(name, ...)
#endif

#ifdef TEST_CUBLAS
#define CUBLAS_SECTION_FUNCTOR(name, ...) , CPM_SECTION_FUNCTOR(name, __VA_ARGS__)
#else
#define CUBLAS_SECTION_FUNCTOR(name, ...)
#endif

#ifdef TEST_CUFFT
#define CUFFT_SECTION_FUNCTOR(name, ...) , CPM_SECTION_FUNCTOR(name, __VA_ARGS__)
#else
#define CUFFT_SECTION_FUNCTOR(name, ...)
#endif

#ifdef TEST_MMUL_CONV
#define MC_SECTION_FUNCTOR(name, ...) , CPM_SECTION_FUNCTOR(name, __VA_ARGS__)
#else
#define MC_SECTION_FUNCTOR(name, ...)
#endif
<|endoftext|>


<commit_before>#include <unordered_set>
#include <vector>
#include <cstdint>

#include "benchmark/benchmark.h"
#include "GenerateInput.hpp"

constexpr std::size_t TestNumInputs = 1024;

template <class GenInputs>
void BM_Sort(benchmark::State& st, GenInputs gen) {
    using ValueType = typename decltype(gen(0))::value_type;
    const auto in = gen(st.range(0));
    std::vector<ValueType> inputs[5];
    auto reset_inputs = [&]() {
        for (auto& C : inputs) {
            C = in;
            benchmark::DoNotOptimize(C.data());
        }
    };
    reset_inputs();
    while (st.KeepRunning()) {
        for (auto& I : inputs) {
            std::sort(I.data(), I.data() + I.size());
            benchmark::DoNotOptimize(I.data());
        }
        st.PauseTiming();
        reset_inputs();
        benchmark::ClobberMemory();
        st.ResumeTiming();
    }
}

BENCHMARK_CAPTURE(BM_Sort, random_uint32,
    getRandomIntegerInputs<uint32_t>)->Arg(TestNumInputs);

BENCHMARK_CAPTURE(BM_Sort, sorted_ascending_uint32,
    getSortedIntegerInputs<uint32_t>)->Arg(TestNumInputs);

BENCHMARK_CAPTURE(BM_Sort, sorted_descending_uint32,
    getReverseSortedIntegerInputs<uint32_t>)->Arg(TestNumInputs);

BENCHMARK_CAPTURE(BM_Sort, single_element_uint32,
    getDuplicateIntegerInputs<uint32_t>)->Arg(TestNumInputs);

BENCHMARK_CAPTURE(BM_Sort, pipe_organ_uint32,
    getPipeOrganIntegerInputs<uint32_t>)->Arg(TestNumInputs);

BENCHMARK_CAPTURE(BM_Sort, random_strings,
    getRandomStringInputs)->Arg(TestNumInputs);

BENCHMARK_CAPTURE(BM_Sort, sorted_ascending_strings,
    getSortedStringInputs)->Arg(TestNumInputs);

BENCHMARK_CAPTURE(BM_Sort, sorted_descending_strings,
    getReverseSortedStringInputs)->Arg(TestNumInputs);

BENCHMARK_CAPTURE(BM_Sort, single_element_strings,
    getDuplicateStringInputs)->Arg(TestNumInputs);

BENCHMARK_MAIN();
<commit_msg>Add benchmarks for sorting and heap functions.<commit_after>
#include <algorithm>
#include <cstdint>
#include <map>
#include <random>
#include <string>
#include <utility>
#include <vector>

#include "CartesianBenchmarks.hpp"
#include "GenerateInput.hpp"
#include "benchmark/benchmark.h"
#include "test_macros.h"

namespace {

enum class ValueType { Uint32, String };
struct AllValueTypes : EnumValuesAsTuple<AllValueTypes, ValueType, 2> {
  static constexpr const char* Names[] = {"uint32", "string"};
};

template <class V>
using Value =
    std::conditional_t<V() == ValueType::Uint32, uint32_t, std::string>;

enum class Order {
  Random,
  Ascending,
  Descending,
  SingleElement,
  PipeOrgan,
  Heap
};
struct AllOrders : EnumValuesAsTuple<AllOrders, Order, 6> {
  static constexpr const char* Names[] = {"Random",     "Ascending",
                                          "Descending", "SingleElement",
                                          "PipeOrgan",  "Heap"};
};

void fillValues(std::vector<uint32_t>& V, size_t N, Order O) {
  if (O == Order::SingleElement) {
    V.resize(N, 0);
  } else {
    while (V.size() < N)
      V.push_back(V.size());
  }
}

void fillValues(std::vector<std::string>& V, size_t N, Order O) {

  if (O == Order::SingleElement) {
    V.resize(N, getRandomString(1024));
  } else {
    while (V.size() < N)
      V.push_back(getRandomString(1024));
  }
}

template <class T>
void sortValues(T& V, Order O) {
  assert(std::is_sorted(V.begin(), V.end()));
  switch (O) {
  case Order::Random: {
    std::random_device R;
    std::mt19937 M(R());
    std::shuffle(V.begin(), V.end(), M);
    break;
  }
  case Order::Ascending:
    std::sort(V.begin(), V.end());
    break;
  case Order::Descending:
    std::sort(V.begin(), V.end(), std::greater<>());
    break;
  case Order::SingleElement:
    // Nothing to do
    break;
  case Order::PipeOrgan:
    std::sort(V.begin(), V.end());
    std::reverse(V.begin() + V.size() / 2, V.end());
    break;
  case Order::Heap:
    std::make_heap(V.begin(), V.end());
    break;
  }
}

template <class ValueType>
std::vector<std::vector<Value<ValueType> > > makeOrderedValues(size_t N,
                                                               Order O) {
  // Let's make sure that all random sequences of the same size are the same.
  // That way we can compare the different algorithms with the same input.
  static std::map<std::pair<size_t, Order>, std::vector<Value<ValueType> > >
      Cached;

  auto& Values = Cached[{N, O}];
  if (Values.empty()) {
    fillValues(Values, N, O);
    sortValues(Values, O);
  };
  const size_t NumCopies = std::max(size_t{1}, 1000 / N);
  return { NumCopies, Values };
}

template <class T, class U>
TEST_ALWAYS_INLINE void resetCopies(benchmark::State& state, T& Copies,
                                    U& Orig) {
  state.PauseTiming();
  for (auto& Copy : Copies)
    Copy = Orig;
  state.ResumeTiming();
}

template <class ValueType, class F>
void runOpOnCopies(benchmark::State& state, size_t Quantity, Order O,
                   bool CountElements, F f) {
  auto Copies = makeOrderedValues<ValueType>(Quantity, O);
  const auto Orig = Copies[0];

  const size_t Batch = CountElements ? Copies.size() * Quantity : Copies.size();
  while (state.KeepRunningBatch(Batch)) {
    for (auto& Copy : Copies) {
      f(Copy);
      benchmark::DoNotOptimize(Copy);
    }
    resetCopies(state, Copies, Orig);
  }
}

template <class ValueType, class Order>
struct Sort {
  size_t Quantity;

  void run(benchmark::State& state) const {
    runOpOnCopies<ValueType>(state, Quantity, Order(), false, [](auto& Copy) {
      std::sort(Copy.begin(), Copy.end());
    });
  }

  bool skip() const { return Order() == ::Order::Heap; }

  std::string name() const {
    return "BM_Sort" + ValueType::name() + Order::name() + "_" +
           std::to_string(Quantity);
  };
};

template <class ValueType, class Order>
struct StableSort {
  size_t Quantity;

  void run(benchmark::State& state) const {
    runOpOnCopies<ValueType>(state, Quantity, Order(), false, [](auto& Copy) {
      std::stable_sort(Copy.begin(), Copy.end());
    });
  }

  bool skip() const { return Order() == ::Order::Heap; }

  std::string name() const {
    return "BM_StableSort" + ValueType::name() + Order::name() + "_" +
           std::to_string(Quantity);
  };
};

template <class ValueType, class Order>
struct MakeHeap {
  size_t Quantity;

  void run(benchmark::State& state) const {
    runOpOnCopies<ValueType>(state, Quantity, Order(), false, [](auto& Copy) {
      std::make_heap(Copy.begin(), Copy.end());
    });
  }

  std::string name() const {
    return "BM_MakeHeap" + ValueType::name() + Order::name() + "_" +
           std::to_string(Quantity);
  };
};

template <class ValueType>
struct SortHeap {
  size_t Quantity;

  void run(benchmark::State& state) const {
    runOpOnCopies<ValueType>(
        state, Quantity, Order::Heap, false,
        [](auto& Copy) { std::sort_heap(Copy.begin(), Copy.end()); });
  }

  std::string name() const {
    return "BM_SortHeap" + ValueType::name() + "_" + std::to_string(Quantity);
  };
};

template <class ValueType, class Order>
struct MakeThenSortHeap {
  size_t Quantity;

  void run(benchmark::State& state) const {
    runOpOnCopies<ValueType>(state, Quantity, Order(), false, [](auto& Copy) {
      std::make_heap(Copy.begin(), Copy.end());
      std::sort_heap(Copy.begin(), Copy.end());
    });
  }

  std::string name() const {
    return "BM_MakeThenSortHeap" + ValueType::name() + Order::name() + "_" +
           std::to_string(Quantity);
  };
};

template <class ValueType, class Order>
struct PushHeap {
  size_t Quantity;

  void run(benchmark::State& state) const {
    runOpOnCopies<ValueType>(state, Quantity, Order(), true, [](auto& Copy) {
      for (auto I = Copy.begin(), E = Copy.end(); I != E; ++I) {
        std::push_heap(Copy.begin(), I + 1);
      }
    });
  }

  bool skip() const { return Order() == ::Order::Heap; }

  std::string name() const {
    return "BM_PushHeap" + ValueType::name() + Order::name() + "_" +
           std::to_string(Quantity);
  };
};

template <class ValueType>
struct PopHeap {
  size_t Quantity;

  void run(benchmark::State& state) const {
    runOpOnCopies<ValueType>(state, Quantity, Order(), true, [](auto& Copy) {
      for (auto B = Copy.begin(), I = Copy.end(); I != B; --I) {
        std::pop_heap(B, I);
      }
    });
  }

  std::string name() const {
    return "BM_PopHeap" + ValueType::name() + "_" + std::to_string(Quantity);
  };
};

} // namespace

int main(int argc, char** argv) {
  benchmark::Initialize(&argc, argv);
  if (benchmark::ReportUnrecognizedArguments(argc, argv))
    return 1;

  const std::vector<size_t> Quantities = {1 << 0, 1 << 2,  1 << 4,  1 << 6,
                                          1 << 8, 1 << 10, 1 << 14, 1 << 18};
  makeCartesianProductBenchmark<Sort, AllValueTypes, AllOrders>(Quantities);
  makeCartesianProductBenchmark<StableSort, AllValueTypes, AllOrders>(
      Quantities);
  makeCartesianProductBenchmark<MakeHeap, AllValueTypes, AllOrders>(Quantities);
  makeCartesianProductBenchmark<SortHeap, AllValueTypes>(Quantities);
  makeCartesianProductBenchmark<MakeThenSortHeap, AllValueTypes, AllOrders>(
      Quantities);
  makeCartesianProductBenchmark<PushHeap, AllValueTypes, AllOrders>(Quantities);
  makeCartesianProductBenchmark<PopHeap, AllValueTypes>(Quantities);
  benchmark::RunSpecifiedBenchmarks();
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 Plenluno All rights reserved.

#include <map>

#include "libj/map.h"
#include "libj/null.h"
#include "libj/string.h"

namespace libj {

class MapImpl : public Map {
 private:
    class ValueComp {
     public:
        Boolean operator() (const Value& lv, const Value& rv) const {
            return lv.compareTo(rv) < 0;
        }
    };

    typedef std::map<Value, Value, ValueComp> ValueMap;

 public:
    Size size() const {
        return map_.size();
    }

    Boolean containsKey(const Value& key) const {
        return map_.find(key) != map_.end();
    }

    Boolean containsValue(const Value& val) const {
        for (ValueMap::const_iterator itr = map_.begin();
             itr != map_.end();
             ++itr) {
            if (!itr->second.compareTo(val))
                return true;
        }
        return false;
    }

    Value get(const Value& key) const {
        ValueMap::const_iterator itr = map_.find(key);
        if (itr != map_.end())
            return itr->second;
        else
            return Null::instance();
    }

    Value put(const Value& key, const Value& val) {
        Value v = get(key);
        map_[key] = val;
        return v;
    }

    Value remove(const Value& key) {
        Value v = get(key);
        map_.erase(key);
        return v;
    }

    Set::CPtr keySet() const {
        Set::Ptr s = Set::create();
        for (ValueMap::const_iterator itr = map_.begin();
             itr != map_.end();
             ++itr) {
            s->add(itr->first);
        }
        return s;
    }

    void clear() {
        map_.clear();
    }

    Map::Ptr clone() const {
        // TODO(plenluno): implement
        Map::Ptr p(new MapImpl());
        return p;
    }

    String::CPtr toString() const {
        // TODO(plenluno): implement
        return String::create();
    }

 private:
    ValueMap map_;
};

Map::Ptr Map::create() {
    Map::Ptr p(new MapImpl());
    return p;
}

}  // namespace libj
<commit_msg>implement Map::toString<commit_after>// Copyright (c) 2012 Plenluno All rights reserved.

#include <map>

#include "libj/map.h"
#include "libj/null.h"
#include "libj/string.h"

namespace libj {

class MapImpl : public Map {
 private:
    class ValueComp {
     public:
        Boolean operator() (const Value& lv, const Value& rv) const {
            return lv.compareTo(rv) < 0;
        }
    };

    typedef std::map<Value, Value, ValueComp> ValueMap;

 public:
    Size size() const {
        return map_.size();
    }

    Boolean containsKey(const Value& key) const {
        return map_.find(key) != map_.end();
    }

    Boolean containsValue(const Value& val) const {
        for (ValueMap::const_iterator itr = map_.begin();
             itr != map_.end();
             ++itr) {
            if (!itr->second.compareTo(val))
                return true;
        }
        return false;
    }

    Value get(const Value& key) const {
        ValueMap::const_iterator itr = map_.find(key);
        if (itr != map_.end())
            return itr->second;
        else
            return Null::instance();
    }

    Value put(const Value& key, const Value& val) {
        Value v = get(key);
        map_[key] = val;
        return v;
    }

    Value remove(const Value& key) {
        Value v = get(key);
        map_.erase(key);
        return v;
    }

    Set::CPtr keySet() const {
        Set::Ptr s = Set::create();
        for (ValueMap::const_iterator itr = map_.begin();
             itr != map_.end();
             ++itr) {
            s->add(itr->first);
        }
        return s;
    }

    void clear() {
        map_.clear();
    }

    String::CPtr toString() const {
        static const String::CPtr lbrace = String::create("{");
        static const String::CPtr rbrace = String::create("}");
        static const String::CPtr eq = String::create("=");
        static const String::CPtr comma = String::create(", ");

        StringBuffer::Ptr sb = StringBuffer::create();
        sb->append(lbrace);
        Boolean first = true;
        Set::CPtr keys = keySet();
        Iterator::Ptr itr = keys->iterator();
        while (itr->hasNext()) {
            Value v = itr->next();
            if (first) {
                first = false;
            } else {
                sb->append(comma);
            }
            sb->append(String::valueOf(v));
            sb->append(eq);
            sb->append(String::valueOf(get(v)));
        }
        sb->append(rbrace);
        return sb->toString();
    }

 private:
    ValueMap map_;
};

Map::Ptr Map::create() {
    Map::Ptr p(new MapImpl());
    return p;
}

}  // namespace libj
<|endoftext|>


<commit_before>// Copyright 2017 Global Phasing Ltd.

#include <cmath>           // for floor
#include <cstdio>          // for fprintf
#include <algorithm>       // for nth_element, count_if
#include "gemmi/ccp4.hpp"
#include "gemmi/gz.hpp"    // for MaybeGzipped
#include "gemmi/util.hpp"  // for trim_str
#include "gemmi/symmetry.hpp"
#include "gemmi/floodfill.hpp"  // for mask_points_above_threshold
#include "histogram.h"     // for print_histogram
#define GEMMI_PROG map
#include "options.h"

namespace {

enum OptionIndex {
  Dump=4, Deltas, CheckSym, Reorder, Full, Mask, Threshold, Fraction
};

const option::Descriptor Usage[] = {
  { NoOp, 0, "", "", Arg::None,
    "Usage:\n " EXE_NAME " [options] CCP4_MAP[...]\n" },
  CommonUsage[Help],
  CommonUsage[Version],
  CommonUsage[Verbose],
  { Dump, 0, "d", "dump", Arg::None,
    "  -d, --dump  \tPrint a map summary (default action)." },
  { Deltas, 0, "", "deltas", Arg::None,
    "  --deltas  \tStatistics of dx, dy and dz." },
  { CheckSym, 0, "", "check-symmetry", Arg::None,
    "  --check-symmetry  \tCompare the values of symmetric points." },
  { Reorder, 0, "", "write-xyz", Arg::Required,
    "  --write-xyz=FILE  \tWrite transposed map with fast X axis and slow Z." },
  { Full, 0, "", "write-full", Arg::Required,
    "  --write-full=FILE  \tWrite map extended to cover whole unit cell." },
  { Mask, 0, "", "write-mask", Arg::Required,
    "  --write-mask=FILE  \tMake a mask by thresholding the map." },
  { NoOp, 0, "", "", Arg::None, "\nOptions for making a mask:" },
  { Threshold, 0, "", "threshold", Arg::Float,
    "  --threshold  \tExplicit threshold value for 0/1 mask." },
  { Fraction, 0, "", "fraction", Arg::Float,
    "  --fraction  \tThreshold is selected to have this fraction of 1's." },
  { 0, 0, 0, 0, 0, 0 }
};

template<typename T>
void print_info(const gemmi::Ccp4<T>& map, const gemmi::DataStats& st) {
  const gemmi::Grid<T>& grid = map.grid;
  std::printf("Map mode: %d\n", map.header_i32(4));
  std::printf("Endiannes: %snative\n", map.same_byte_order ? "" : "NOT ");
  std::printf("Number of columns, rows, sections: %5d %5d %5d %6s %d points\n",
              grid.nu, grid.nv, grid.nw, "->", grid.nu * grid.nv * grid.nw);
  int u0 = map.header_i32(5);
  int v0 = map.header_i32(6);
  int w0 = map.header_i32(7);
  std::printf("                             from: %5d %5d %5d\n", u0, v0, w0);
  std::printf("                               to: %5d %5d %5d\n",
              u0 + grid.nu - 1, v0 + grid.nv - 1, w0 + grid.nw - 1);
  std::printf("Fast, medium, slow axes: %c %c %c\n",
              'X' + map.header_i32(17) - 1,
              'X' + map.header_i32(18) - 1,
              'X' + map.header_i32(19) - 1);
  int mx = map.header_i32(8);
  int my = map.header_i32(9);
  int mz = map.header_i32(10);
  std::printf("Grid sampling on x, y, z: %5d %5d %5d    %12s %d points/cell\n",
              mx, my, mz, "->", mx * my * mz);
  const gemmi::UnitCell& cell = grid.unit_cell;
  const gemmi::SpaceGroup* sg = grid.spacegroup;
  std::printf("Space group: %d  (%s)\n",
              sg ? sg->ccp4 : 0, sg ? sg->hm : "unknown");
  int order = sg ? sg->operations().order() : 1;
  std::printf("SG order: %-3d      %40s %d points/ASU\n",
               order, "->", mx * my * mz / order);
  std::printf("Cell dimensions: %g %g %g  %g %g %g\n",
              cell.a, cell.b, cell.c, cell.alpha, cell.beta, cell.gamma);
  int origin[3] = {
    map.header_i32(50),
    map.header_i32(51),
    map.header_i32(52)
  };
  if (origin[0] != 0 || origin[1] != 0 || origin[2] != 0)
    std::printf("Non-zero origin: %d %d %d\n", origin[0], origin[1], origin[2]);
  if (map.has_skew_transformation())
    std::printf("Defines skew transformation with translation length %.5g A.\n",
                map.get_skew_transformation().vec.length());

  if (st.nan_count != 0)
    std::printf("\n*** Data includes NaNs: %zu of %zu points ***",
                st.nan_count, grid.data.size());
  std::printf("\nStatistics from HEADER and DATA\n");
  std::printf("Minimum: %12.5f  %12.5f\n", map.hstats.dmin, st.dmin);
  std::printf("Maximum: %12.5f  %12.5f\n", map.hstats.dmax, st.dmax);
  std::printf("Mean:    %12.5f  %12.5f\n", map.hstats.dmean, st.dmean);
  std::printf("RMS:     %12.5f  %12.5f\n", map.hstats.rms, st.rms);
  std::vector<T> data = grid.data;  // copy b/c nth_element() reorders data
  if (st.nan_count != 0)
    gemmi::vector_remove_if(data, [](T x) { return std::isnan(x); });
  if (!data.empty()) {
    size_t mpos = data.size() / 2;
    std::nth_element(data.begin(), data.begin() + mpos, data.end());
    std::printf("Median:                %12.5f\n", data[mpos]);
    bool mask = std::all_of(data.begin(), data.end(),
                            [&st](T x) { return x == st.dmin || x == st.dmax; });
    double margin = mask ? 7 * (st.dmax - st.dmin) : 0;
    print_histogram(data, st.dmin - margin, st.dmax + margin);
  }

  int nlabl = map.header_i32(56);
  if (nlabl != 0)
    std::printf("\n");
  for (int i = 0; i < nlabl && i < 10; ++i) {
    std::string label = gemmi::trim_str(map.header_str(57 + i * 20));
    std::printf("Label #%d\n%s\n", i, label.c_str());
  }
  int nsymbt = map.header_i32(24);
  if (nsymbt != 0) {
    std::printf("\n");
    std::vector<gemmi::Op> ops;
    int bad_counter = 0;
    for (int i = 0; i * 80 < nsymbt; i++) {
      std::string symop = map.header_str(256 + i * 20 /*words not bytes*/, 80);
      try {
        gemmi::Op op = gemmi::parse_triplet(symop);
        ops.push_back(op);
      } catch (std::exception&) {
        ++bad_counter;
      }
      std::printf("Sym op #%d: %s\n", i + 1, gemmi::trim_str(symop).c_str());
    }
    if (bad_counter == 0) {
      gemmi::GroupOps gops = gemmi::split_centering_vectors(ops);
      const gemmi::SpaceGroup* sg2 = gemmi::find_spacegroup_by_ops(gops);
      std::printf("Space group from the operators: ");
      if (sg2)
        std::printf("%d  (%s)\n", sg->ccp4, sg->xhm().c_str());
      else
        std::printf("unknown\n");
      if (sg2 && sg && sg != sg2)
        std::printf("NOTE: different than from the ISPG header.\n");
    } else {
      std::printf("NOTE: %d of symmetry lines do not parse as operators.\n", bad_counter);
    }
  }
}

template<typename T>
void print_deltas(const gemmi::Grid<T>& grid, double dmin, double dmax) {
  std::vector<double> deltas;
  deltas.reserve(grid.data.size());
  for (int i = 0; i < 3; ++i) {
    int f[3] = {0, 0, 0};
    f[i] = 1;
    for (int w = f[2]; w < grid.nw; ++w)
      for (int v = f[1]; v < grid.nv; ++v)
        for (int u = f[0]; u < grid.nu; ++u)
          deltas.push_back(grid.get_value_q(u, v, w) -
                           grid.get_value_q(u - f[0], v - f[1], w - f[2]));
    gemmi::DataStats st = gemmi::calculate_data_statistics(deltas);
    std::printf("\nd%c: min: %.5f  max: %.5f  mean: %.5f  std.dev: %.5f\n",
                "XYZ"[i], st.dmin, st.dmax, st.dmean, st.rms);
    print_histogram(deltas, dmin, dmax);
    deltas.clear();
  }
}

} // anonymous namespace

int GEMMI_MAIN(int argc, char **argv) {
  OptParser p(EXE_NAME);
  p.simple_parse(argc, argv, Usage);
  p.require_input_files_as_args();
  p.check_exclusive_pair(Threshold, Fraction);
  //bool verbose = p.options[Verbose];

  if (p.nonOptionsCount() > 1 && (p.options[Reorder] || p.options[Full])) {
    std::fprintf(stderr, "Option --write-... can be only used "
                         "with a single input file.\n");
    return 1;
  }

  bool dump = (p.options[Dump] ||
               !(p.options[Deltas] || p.options[CheckSym] ||
                 p.options[Reorder] || p.options[Full] || p.options[Mask]));
  try {
    for (int i = 0; i < p.nonOptionsCount(); ++i) {
      const char* input = p.nonOption(i);
      gemmi::Ccp4<> map;
      if (i != 0)
        std::printf("\n\n");
      std::printf("Reading file: %s\n", input);
      map.read_ccp4(gemmi::MaybeGzipped(input));
      gemmi::DataStats stats = gemmi::calculate_data_statistics(map.grid.data);
      if (dump)
        print_info(map, stats);
      if (p.options[Deltas])
        print_deltas(map.grid, stats.dmin, stats.dmax);
      if (p.options[Reorder]) {
        map.setup(NAN, gemmi::MapSetup::ReorderOnly);
        map.write_ccp4_map(p.options[Reorder].arg);
      }
      double max_err = 0.;
      if (p.options[CheckSym]) {
        const double eps = 0.01;
        // this is equivalent to calling map.setup(Full), but additionally
        // it prints inconsistent points.
        map.setup(NAN, gemmi::MapSetup::NoSymmetry);
        map.grid.axis_order = gemmi::AxisOrder::XYZ;
        map.grid.symmetrize([&](float a, float b) {
            if (a < b || a > b) {
              double diff = std::fabs(a - b);
              if (diff > eps)
                std::printf("Symmetry-equivalent values differ: "
                            "%g != %g  diff: %g\n", a, b, diff);
              max_err = std::max(max_err, diff);
            }
            return std::isnan(a) ? b : a;
        });
        map.grid.calculate_spacing();
      } else if (p.options[Full] || p.options[Mask]) {
        max_err = map.setup(NAN, gemmi::MapSetup::Full);
      }
      if (max_err != 0.0)
        std::fprintf(stderr, "WARNING: different values for equivalent "
                             "points, max diff: %g\n", max_err);
      if (p.options[Full]) {
        size_t nn = std::count_if(map.grid.data.begin(), map.grid.data.end(),
                                  [](float x) { return std::isnan(x); });
        if (nn != 0)
          std::fprintf(stderr, "WARNING: %zu unknown values set to NAN\n", nn);
        map.write_ccp4_map(p.options[Full].arg);
      }
      if (p.options[Mask]) {
        double threshold;
        if (p.options[Threshold]) {
          threshold = std::atof(p.options[Threshold].arg);
        } else if (p.options[Fraction]) {
          double fraction = std::atof(p.options[Fraction].arg);
          if (fraction < 0. || fraction > 1.) {
            std::fprintf(stderr, "Fraction must be between 0 and 1.\n");
            return 2;
          }
          auto data = map.grid.data;  // making a copy for nth_element()
          size_t n = std::min(static_cast<size_t>(data.size() * (1.0 - fraction)),
                              data.size() - 1);
          std::nth_element(data.begin(), data.begin() + n, data.end());
          threshold = data[n];
        } else {
          std::fprintf(stderr, "ERROR: you need to use --threshold or --fraction.\n");
          return 2;
        }
        gemmi::Ccp4<std::int8_t> mask;
        gemmi::mask_nodes_above_threshold(mask.grid, map.grid, threshold);
        size_t ones = std::count(mask.grid.data.begin(), mask.grid.data.end(), 1);
        size_t all = mask.grid.data.size();
        std::fprintf(stderr, "Masked %zu of %zu points (%.1f%%) above %g\n",
                     ones, all, 100.0 * ones / all, threshold);
        mask.update_ccp4_header(0);
        mask.write_ccp4_map(p.options[Mask].arg);
      }
    }
  } catch (std::runtime_error& e) {
    std::fprintf(stderr, "ERROR: %s\n", e.what());
    return 1;
  }
  return 0;
}
<commit_msg>gemmi-map: fix output<commit_after>// Copyright 2017 Global Phasing Ltd.

#include <cmath>           // for floor
#include <cstdio>          // for fprintf
#include <algorithm>       // for nth_element, count_if
#include "gemmi/ccp4.hpp"
#include "gemmi/gz.hpp"    // for MaybeGzipped
#include "gemmi/util.hpp"  // for trim_str
#include "gemmi/symmetry.hpp"
#include "gemmi/floodfill.hpp"  // for mask_points_above_threshold
#include "histogram.h"     // for print_histogram
#define GEMMI_PROG map
#include "options.h"

namespace {

enum OptionIndex {
  Dump=4, Deltas, CheckSym, Reorder, Full, Mask, Threshold, Fraction
};

const option::Descriptor Usage[] = {
  { NoOp, 0, "", "", Arg::None,
    "Usage:\n " EXE_NAME " [options] CCP4_MAP[...]\n" },
  CommonUsage[Help],
  CommonUsage[Version],
  CommonUsage[Verbose],
  { Dump, 0, "d", "dump", Arg::None,
    "  -d, --dump  \tPrint a map summary (default action)." },
  { Deltas, 0, "", "deltas", Arg::None,
    "  --deltas  \tStatistics of dx, dy and dz." },
  { CheckSym, 0, "", "check-symmetry", Arg::None,
    "  --check-symmetry  \tCompare the values of symmetric points." },
  { Reorder, 0, "", "write-xyz", Arg::Required,
    "  --write-xyz=FILE  \tWrite transposed map with fast X axis and slow Z." },
  { Full, 0, "", "write-full", Arg::Required,
    "  --write-full=FILE  \tWrite map extended to cover whole unit cell." },
  { Mask, 0, "", "write-mask", Arg::Required,
    "  --write-mask=FILE  \tMake a mask by thresholding the map." },
  { NoOp, 0, "", "", Arg::None, "\nOptions for making a mask:" },
  { Threshold, 0, "", "threshold", Arg::Float,
    "  --threshold  \tExplicit threshold value for 0/1 mask." },
  { Fraction, 0, "", "fraction", Arg::Float,
    "  --fraction  \tThreshold is selected to have this fraction of 1's." },
  { 0, 0, 0, 0, 0, 0 }
};

template<typename T>
void print_info(const gemmi::Ccp4<T>& map, const gemmi::DataStats& st) {
  const gemmi::Grid<T>& grid = map.grid;
  std::printf("Map mode: %d\n", map.header_i32(4));
  std::printf("Endiannes: %snative\n", map.same_byte_order ? "" : "NOT ");
  std::printf("Number of columns, rows, sections: %5d %5d %5d %6s %d points\n",
              grid.nu, grid.nv, grid.nw, "->", grid.nu * grid.nv * grid.nw);
  int u0 = map.header_i32(5);
  int v0 = map.header_i32(6);
  int w0 = map.header_i32(7);
  std::printf("                             from: %5d %5d %5d\n", u0, v0, w0);
  std::printf("                               to: %5d %5d %5d\n",
              u0 + grid.nu - 1, v0 + grid.nv - 1, w0 + grid.nw - 1);
  std::printf("Fast, medium, slow axes: %c %c %c\n",
              'X' + map.header_i32(17) - 1,
              'X' + map.header_i32(18) - 1,
              'X' + map.header_i32(19) - 1);
  int mx = map.header_i32(8);
  int my = map.header_i32(9);
  int mz = map.header_i32(10);
  std::printf("Grid sampling on x, y, z: %5d %5d %5d    %12s %d points/cell\n",
              mx, my, mz, "->", mx * my * mz);
  const gemmi::UnitCell& cell = grid.unit_cell;
  const gemmi::SpaceGroup* sg = grid.spacegroup;
  std::printf("Space group: %d  (%s)\n",
              sg ? sg->ccp4 : 0, sg ? sg->hm : "unknown");
  int order = sg ? sg->operations().order() : 1;
  std::printf("SG order: %-3d      %40s %d points/ASU\n",
               order, "->", mx * my * mz / order);
  std::printf("Cell dimensions: %g %g %g  %g %g %g\n",
              cell.a, cell.b, cell.c, cell.alpha, cell.beta, cell.gamma);
  int origin[3] = {
    map.header_i32(50),
    map.header_i32(51),
    map.header_i32(52)
  };
  if (origin[0] != 0 || origin[1] != 0 || origin[2] != 0)
    std::printf("Non-zero origin: %d %d %d\n", origin[0], origin[1], origin[2]);
  if (map.has_skew_transformation())
    std::printf("Defines skew transformation with translation length %.5g A.\n",
                map.get_skew_transformation().vec.length());

  if (st.nan_count != 0)
    std::printf("\n*** Data includes NaNs: %zu of %zu points ***",
                st.nan_count, grid.data.size());
  std::printf("\nStatistics from HEADER and DATA\n");
  std::printf("Minimum: %12.5f  %12.5f\n", map.hstats.dmin, st.dmin);
  std::printf("Maximum: %12.5f  %12.5f\n", map.hstats.dmax, st.dmax);
  std::printf("Mean:    %12.5f  %12.5f\n", map.hstats.dmean, st.dmean);
  std::printf("RMS:     %12.5f  %12.5f\n", map.hstats.rms, st.rms);
  std::vector<T> data = grid.data;  // copy b/c nth_element() reorders data
  if (st.nan_count != 0)
    gemmi::vector_remove_if(data, [](T x) { return std::isnan(x); });
  if (!data.empty()) {
    size_t mpos = data.size() / 2;
    std::nth_element(data.begin(), data.begin() + mpos, data.end());
    std::printf("Median:                %12.5f\n", data[mpos]);
    bool mask = std::all_of(data.begin(), data.end(),
                            [&st](T x) { return x == st.dmin || x == st.dmax; });
    double margin = mask ? 7 * (st.dmax - st.dmin) : 0;
    print_histogram(data, st.dmin - margin, st.dmax + margin);
  }

  int nlabl = map.header_i32(56);
  if (nlabl != 0)
    std::printf("\n");
  for (int i = 0; i < nlabl && i < 10; ++i) {
    std::string label = gemmi::trim_str(map.header_str(57 + i * 20));
    std::printf("Label #%d\n%s\n", i, label.c_str());
  }
  int nsymbt = map.header_i32(24);
  if (nsymbt != 0) {
    std::printf("\n");
    std::vector<gemmi::Op> ops;
    int bad_counter = 0;
    for (int i = 0; i * 80 < nsymbt; i++) {
      std::string symop = map.header_str(256 + i * 20 /*words not bytes*/, 80);
      try {
        gemmi::Op op = gemmi::parse_triplet(symop);
        ops.push_back(op);
      } catch (std::exception&) {
        ++bad_counter;
      }
      std::printf("Sym op #%d: %s\n", i + 1, gemmi::trim_str(symop).c_str());
    }
    if (bad_counter == 0) {
      gemmi::GroupOps gops = gemmi::split_centering_vectors(ops);
      const gemmi::SpaceGroup* sg2 = gemmi::find_spacegroup_by_ops(gops);
      std::printf("Space group from the operators: ");
      if (sg2)
        std::printf("%d  (%s)\n", sg2->ccp4, sg2->xhm().c_str());
      else
        std::printf("unknown\n");
      if (sg2 && sg && sg != sg2)
        std::printf("NOTE: different than from the ISPG header.\n");
    } else {
      std::printf("NOTE: %d of symmetry lines do not parse as operators.\n", bad_counter);
    }
  }
}

template<typename T>
void print_deltas(const gemmi::Grid<T>& grid, double dmin, double dmax) {
  std::vector<double> deltas;
  deltas.reserve(grid.data.size());
  for (int i = 0; i < 3; ++i) {
    int f[3] = {0, 0, 0};
    f[i] = 1;
    for (int w = f[2]; w < grid.nw; ++w)
      for (int v = f[1]; v < grid.nv; ++v)
        for (int u = f[0]; u < grid.nu; ++u)
          deltas.push_back(grid.get_value_q(u, v, w) -
                           grid.get_value_q(u - f[0], v - f[1], w - f[2]));
    gemmi::DataStats st = gemmi::calculate_data_statistics(deltas);
    std::printf("\nd%c: min: %.5f  max: %.5f  mean: %.5f  std.dev: %.5f\n",
                "XYZ"[i], st.dmin, st.dmax, st.dmean, st.rms);
    print_histogram(deltas, dmin, dmax);
    deltas.clear();
  }
}

} // anonymous namespace

int GEMMI_MAIN(int argc, char **argv) {
  OptParser p(EXE_NAME);
  p.simple_parse(argc, argv, Usage);
  p.require_input_files_as_args();
  p.check_exclusive_pair(Threshold, Fraction);
  //bool verbose = p.options[Verbose];

  if (p.nonOptionsCount() > 1 && (p.options[Reorder] || p.options[Full])) {
    std::fprintf(stderr, "Option --write-... can be only used "
                         "with a single input file.\n");
    return 1;
  }

  bool dump = (p.options[Dump] ||
               !(p.options[Deltas] || p.options[CheckSym] ||
                 p.options[Reorder] || p.options[Full] || p.options[Mask]));
  try {
    for (int i = 0; i < p.nonOptionsCount(); ++i) {
      const char* input = p.nonOption(i);
      gemmi::Ccp4<> map;
      if (i != 0)
        std::printf("\n\n");
      std::printf("Reading file: %s\n", input);
      map.read_ccp4(gemmi::MaybeGzipped(input));
      gemmi::DataStats stats = gemmi::calculate_data_statistics(map.grid.data);
      if (dump)
        print_info(map, stats);
      if (p.options[Deltas])
        print_deltas(map.grid, stats.dmin, stats.dmax);
      if (p.options[Reorder]) {
        map.setup(NAN, gemmi::MapSetup::ReorderOnly);
        map.write_ccp4_map(p.options[Reorder].arg);
      }
      double max_err = 0.;
      if (p.options[CheckSym]) {
        const double eps = 0.01;
        // this is equivalent to calling map.setup(Full), but additionally
        // it prints inconsistent points.
        map.setup(NAN, gemmi::MapSetup::NoSymmetry);
        map.grid.axis_order = gemmi::AxisOrder::XYZ;
        map.grid.symmetrize([&](float a, float b) {
            if (a < b || a > b) {
              double diff = std::fabs(a - b);
              if (diff > eps)
                std::printf("Symmetry-equivalent values differ: "
                            "%g != %g  diff: %g\n", a, b, diff);
              max_err = std::max(max_err, diff);
            }
            return std::isnan(a) ? b : a;
        });
        map.grid.calculate_spacing();
      } else if (p.options[Full] || p.options[Mask]) {
        max_err = map.setup(NAN, gemmi::MapSetup::Full);
      }
      if (max_err != 0.0)
        std::fprintf(stderr, "WARNING: different values for equivalent "
                             "points, max diff: %g\n", max_err);
      if (p.options[Full]) {
        size_t nn = std::count_if(map.grid.data.begin(), map.grid.data.end(),
                                  [](float x) { return std::isnan(x); });
        if (nn != 0)
          std::fprintf(stderr, "WARNING: %zu unknown values set to NAN\n", nn);
        map.write_ccp4_map(p.options[Full].arg);
      }
      if (p.options[Mask]) {
        double threshold;
        if (p.options[Threshold]) {
          threshold = std::atof(p.options[Threshold].arg);
        } else if (p.options[Fraction]) {
          double fraction = std::atof(p.options[Fraction].arg);
          if (fraction < 0. || fraction > 1.) {
            std::fprintf(stderr, "Fraction must be between 0 and 1.\n");
            return 2;
          }
          auto data = map.grid.data;  // making a copy for nth_element()
          size_t n = std::min(static_cast<size_t>(data.size() * (1.0 - fraction)),
                              data.size() - 1);
          std::nth_element(data.begin(), data.begin() + n, data.end());
          threshold = data[n];
        } else {
          std::fprintf(stderr, "ERROR: you need to use --threshold or --fraction.\n");
          return 2;
        }
        gemmi::Ccp4<std::int8_t> mask;
        gemmi::mask_nodes_above_threshold(mask.grid, map.grid, threshold);
        size_t ones = std::count(mask.grid.data.begin(), mask.grid.data.end(), 1);
        size_t all = mask.grid.data.size();
        std::fprintf(stderr, "Masked %zu of %zu points (%.1f%%) above %g\n",
                     ones, all, 100.0 * ones / all, threshold);
        mask.update_ccp4_header(0);
        mask.write_ccp4_map(p.options[Mask].arg);
      }
    }
  } catch (std::runtime_error& e) {
    std::fprintf(stderr, "ERROR: %s\n", e.what());
    return 1;
  }
  return 0;
}
<|endoftext|>