<commit_before>#ifndef DUNE_COMMON_COLOR_HH
#define DUNE_COMMON_COLOR_HH

#include <sstream>
#include <assert.h>
#include <iostream>

#ifdef __GNUC__
 #include <cxxabi.h>
#endif
#include <string>

#include <dune/stuff/common/string.hh>

namespace Dune {
namespace Stuff {
namespace Common {

/**
 * @brief namespace to define color constants that can be
 * used to print colored text in an output stream.
 *
 * * \todo this could go into libdune-stuff
 * @warning Some color codes might be unsupported by your terminal.
 */
struct Colors {

#define DS_CONST_CHAR const constexpr char*

// foreground colors
static DS_CONST_CHAR black = "\033[30m";
static DS_CONST_CHAR red = "\033[31m";
static DS_CONST_CHAR green = "\033[32m";
static DS_CONST_CHAR brown = "\033[33m";
static DS_CONST_CHAR blue = "\033[34m";
static DS_CONST_CHAR purple = "\033[35m";
static DS_CONST_CHAR cyan = "\033[36m";
static DS_CONST_CHAR lightgray = "\033[37m";
// light foreground colors
static DS_CONST_CHAR darkgray = "\033[1;30m";
static DS_CONST_CHAR lightred = "\033[1;31m";
static DS_CONST_CHAR lightgreen = "\033[1;32m";
static DS_CONST_CHAR yellow = "\033[1;33m";
static DS_CONST_CHAR lightblue = "\033[1;34m";
static DS_CONST_CHAR lightpurple = "\033[1;35m";
static DS_CONST_CHAR lightcyan = "\033[1;36m";
static DS_CONST_CHAR white = "\033[1;37m";

// background colors
static DS_CONST_CHAR bblack = "\033[40m";
static DS_CONST_CHAR bred = "\033[41m";
static DS_CONST_CHAR bgreen = "\033[42m";
static DS_CONST_CHAR bbrown = "\033[43m";
static DS_CONST_CHAR bblue = "\033[44m";
static DS_CONST_CHAR bpurple = "\033[45m";
static DS_CONST_CHAR bcyan = "\033[46m";
static DS_CONST_CHAR blightgray = "\033[47m";
// light background colors
static DS_CONST_CHAR bdarkgray = "\033[1;40m";
static DS_CONST_CHAR blightred = "\033[1;41m";
static DS_CONST_CHAR blightgreen = "\033[1;42m";
static DS_CONST_CHAR byellow = "\033[1;43m";
static DS_CONST_CHAR blightblue = "\033[1;44m";
static DS_CONST_CHAR blightpurple = "\033[1;45m";
static DS_CONST_CHAR blightcyan = "\033[1;46m";
static DS_CONST_CHAR bwhite = "\033[1;47m";
};
// modifiers
struct StreamModifiers {
static DS_CONST_CHAR normal = "\033[0m";
static DS_CONST_CHAR bold = "\033[1m";
static DS_CONST_CHAR italic = "\033[2m";
static DS_CONST_CHAR underline = "\033[4m";
static DS_CONST_CHAR blink = "\033[5m";
static DS_CONST_CHAR reverse = "\033[7m";
static DS_CONST_CHAR enditalic = "\033[22m";
static DS_CONST_CHAR endunderline = "\033[24m";
static DS_CONST_CHAR endblink = "\033[25m";
static DS_CONST_CHAR endreverse = "\033[27m";
#undef DS_CONST_CHAR
};
/**
 * @brief Chooses a color from a 256 color map for a foreground color.
 *
 * @param i The color number between 0 and 255.
 * @returns A string describing a color code.
 */
std::string color(int i) {
  return "\033[38;5;" + toString(i) + "m";
}

/**
 * @brief Chooses a color from a 256 color map for a background color.
 *
 * @param i The color number between 0 and 255.
 * @returns A string describing a color code.
 */
std::string backcolor(int i) {
  return "\033[38;5;" + toString(i) + "m";
}

// maybe you want to choose your own color
int templateColorChooser(int i) {
  return i % 256;
}

/**
 * @brief Highlights templates depending on the "template"-level.
 *
 * @param str The string containing the template string
 * @param maxlevel The maximal template-level the string is reduced to.
 * @returns A colored template string.
 */
std::string highlightTemplate(std::string str, int maxlevel = 10000) {
  if (maxlevel < 0)
    maxlevel = 0;
  int startindex = 0;
  int level = 0;
  for (size_t i = 0; i < str.size(); i++)
  {
    if (str[i] == '<')
    {
      level++;
      std::string dummy = "\033[38;5;" + toString( templateColorChooser(level) ) + "m";
      str.insert(i, dummy);
      i += dummy.size();
      if (level == maxlevel)
        startindex = i + 1;
    } else if (str[i] == '>') {
      level--;
      std::string dummy = "\033[38;5;" + toString( templateColorChooser(level) ) + "m";
      str.insert(++i, dummy);
      if (level + 1 == maxlevel)
      {
        int size = i - startindex - 1;
        str.erase(startindex, size);
        i = startindex + 1;
      }
      i += dummy.size();
    }
  }
  str += "\033[38;5;0m";
  return str;
} // highlightTemplate

/**
 * @brief A simple function highlighting a whole string in a specified foreground color.
 *
 * @param str The string you want to highlight.
 * @param colornr A color number from a 256 color map between 0 and 255.
 * @returns The highlighted string.
 */
std::string highlightString(std::string str, int colornr = 0) {
  return "\033[38;5;" + toString(colornr % 256) + "m" + str + "\033[0m"; //"\033[38;5;0m";
}

std::string colorString(const std::string string, const std::string color = Colors::brown)
{
  return color + string + "\033[0m";
}

/**
 * @brief Highlights a substring of another string in a specified color.
 *
 * @param str The string where you want to highlight substrings.
 * @param substr The sub string you want to highlight in str.
 * @param colornr A color number from a 256 color map between 0 and 255.
 * @returns The highlighted string.
 */
std::string highlightSearchString(std::string str, std::string substr, int colornr = 0) {
  int index = str.find(substr, 0);

  while ( index != int(std::string::npos) )
  {
    std::string dummy = "\033[38;5;" + toString(colornr % 256) + "m";
    std::string dummy2 = "\033[38;5;0m";
    str.insert(index, dummy);
    str.insert(index + substr.size() + dummy.size(), dummy2);
    index = str.find( substr, index + dummy.size() + substr.size() + dummy2.size() );
  }
  return str;
} // highlightSearchString

} // namespace Common
} // namespace Stuff
} // namespace Dune

#endif // end of DUNE_COMMON_COLOR_HH

/** Copyright (c) 2012, Stefan Girke
   * 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.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * The views and conclusions contained in the software and documentation are those
   * of the authors and should not be interpreted as representing official policies,
   * either expressed or implied, of the FreeBSD Project.
   **/
<commit_msg>[common.color] added colorStringRed() since I'm lazy<commit_after>#ifndef DUNE_COMMON_COLOR_HH
#define DUNE_COMMON_COLOR_HH

#include <sstream>
#include <assert.h>
#include <iostream>

#ifdef __GNUC__
 #include <cxxabi.h>
#endif
#include <string>

#include <dune/stuff/common/string.hh>

namespace Dune {
namespace Stuff {
namespace Common {

/**
 * @brief namespace to define color constants that can be
 * used to print colored text in an output stream.
 *
 * * \todo this could go into libdune-stuff
 * @warning Some color codes might be unsupported by your terminal.
 */
struct Colors {

#define DS_CONST_CHAR const constexpr char*

// foreground colors
static DS_CONST_CHAR black = "\033[30m";
static DS_CONST_CHAR red = "\033[31m";
static DS_CONST_CHAR green = "\033[32m";
static DS_CONST_CHAR brown = "\033[33m";
static DS_CONST_CHAR blue = "\033[34m";
static DS_CONST_CHAR purple = "\033[35m";
static DS_CONST_CHAR cyan = "\033[36m";
static DS_CONST_CHAR lightgray = "\033[37m";
// light foreground colors
static DS_CONST_CHAR darkgray = "\033[1;30m";
static DS_CONST_CHAR lightred = "\033[1;31m";
static DS_CONST_CHAR lightgreen = "\033[1;32m";
static DS_CONST_CHAR yellow = "\033[1;33m";
static DS_CONST_CHAR lightblue = "\033[1;34m";
static DS_CONST_CHAR lightpurple = "\033[1;35m";
static DS_CONST_CHAR lightcyan = "\033[1;36m";
static DS_CONST_CHAR white = "\033[1;37m";

// background colors
static DS_CONST_CHAR bblack = "\033[40m";
static DS_CONST_CHAR bred = "\033[41m";
static DS_CONST_CHAR bgreen = "\033[42m";
static DS_CONST_CHAR bbrown = "\033[43m";
static DS_CONST_CHAR bblue = "\033[44m";
static DS_CONST_CHAR bpurple = "\033[45m";
static DS_CONST_CHAR bcyan = "\033[46m";
static DS_CONST_CHAR blightgray = "\033[47m";
// light background colors
static DS_CONST_CHAR bdarkgray = "\033[1;40m";
static DS_CONST_CHAR blightred = "\033[1;41m";
static DS_CONST_CHAR blightgreen = "\033[1;42m";
static DS_CONST_CHAR byellow = "\033[1;43m";
static DS_CONST_CHAR blightblue = "\033[1;44m";
static DS_CONST_CHAR blightpurple = "\033[1;45m";
static DS_CONST_CHAR blightcyan = "\033[1;46m";
static DS_CONST_CHAR bwhite = "\033[1;47m";
};
// modifiers
struct StreamModifiers {
static DS_CONST_CHAR normal = "\033[0m";
static DS_CONST_CHAR bold = "\033[1m";
static DS_CONST_CHAR italic = "\033[2m";
static DS_CONST_CHAR underline = "\033[4m";
static DS_CONST_CHAR blink = "\033[5m";
static DS_CONST_CHAR reverse = "\033[7m";
static DS_CONST_CHAR enditalic = "\033[22m";
static DS_CONST_CHAR endunderline = "\033[24m";
static DS_CONST_CHAR endblink = "\033[25m";
static DS_CONST_CHAR endreverse = "\033[27m";
#undef DS_CONST_CHAR
};
/**
 * @brief Chooses a color from a 256 color map for a foreground color.
 *
 * @param i The color number between 0 and 255.
 * @returns A string describing a color code.
 */
std::string color(int i) {
  return "\033[38;5;" + toString(i) + "m";
}

/**
 * @brief Chooses a color from a 256 color map for a background color.
 *
 * @param i The color number between 0 and 255.
 * @returns A string describing a color code.
 */
std::string backcolor(int i) {
  return "\033[38;5;" + toString(i) + "m";
}

// maybe you want to choose your own color
int templateColorChooser(int i) {
  return i % 256;
}

/**
 * @brief Highlights templates depending on the "template"-level.
 *
 * @param str The string containing the template string
 * @param maxlevel The maximal template-level the string is reduced to.
 * @returns A colored template string.
 */
std::string highlightTemplate(std::string str, int maxlevel = 10000) {
  if (maxlevel < 0)
    maxlevel = 0;
  int startindex = 0;
  int level = 0;
  for (size_t i = 0; i < str.size(); i++)
  {
    if (str[i] == '<')
    {
      level++;
      std::string dummy = "\033[38;5;" + toString( templateColorChooser(level) ) + "m";
      str.insert(i, dummy);
      i += dummy.size();
      if (level == maxlevel)
        startindex = i + 1;
    } else if (str[i] == '>') {
      level--;
      std::string dummy = "\033[38;5;" + toString( templateColorChooser(level) ) + "m";
      str.insert(++i, dummy);
      if (level + 1 == maxlevel)
      {
        int size = i - startindex - 1;
        str.erase(startindex, size);
        i = startindex + 1;
      }
      i += dummy.size();
    }
  }
  str += "\033[38;5;0m";
  return str;
} // highlightTemplate

/**
 * @brief A simple function highlighting a whole string in a specified foreground color.
 *
 * @param str The string you want to highlight.
 * @param colornr A color number from a 256 color map between 0 and 255.
 * @returns The highlighted string.
 */
std::string highlightString(std::string str, int colornr = 0) {
  return "\033[38;5;" + toString(colornr % 256) + "m" + str + "\033[0m"; //"\033[38;5;0m";
}

std::string colorString(const std::string _string, const std::string _color = Colors::brown)
{
  return _color + _string + "\033[0m";
}

std::string colorStringRed(const std::string _string)
{
  return colorString(_string, Colors::red);
}

/**
 * @brief Highlights a substring of another string in a specified color.
 *
 * @param str The string where you want to highlight substrings.
 * @param substr The sub string you want to highlight in str.
 * @param colornr A color number from a 256 color map between 0 and 255.
 * @returns The highlighted string.
 */
std::string highlightSearchString(std::string str, std::string substr, int colornr = 0) {
  int index = str.find(substr, 0);

  while ( index != int(std::string::npos) )
  {
    std::string dummy = "\033[38;5;" + toString(colornr % 256) + "m";
    std::string dummy2 = "\033[38;5;0m";
    str.insert(index, dummy);
    str.insert(index + substr.size() + dummy.size(), dummy2);
    index = str.find( substr, index + dummy.size() + substr.size() + dummy2.size() );
  }
  return str;
} // highlightSearchString

} // namespace Common
} // namespace Stuff
} // namespace Dune

#endif // end of DUNE_COMMON_COLOR_HH

/** Copyright (c) 2012, Stefan Girke
   * 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.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * The views and conclusions contained in the software and documentation are those
   * of the authors and should not be interpreted as representing official policies,
   * either expressed or implied, of the FreeBSD Project.
   **/
<|endoftext|>


<commit_before>#include "SqlFieldSet.h"

namespace sql
{

FieldSet::FieldSet(Field* definition)
{
	//make fields map from array
	if (definition)
	{
		int index = 0;
		while (true)
		{
			Field& field = definition[index];

			if (field.isEndingField())
				break;

			field._index = index;

			_vec.push_back(field);
			_map[field.getName()] = &field;

			index++;
		}
	}
}

FieldSet::FieldSet(std::vector<Field>& definition)
{
	copy(definition);
}

FieldSet::FieldSet(const FieldSet& source)
{
	copy(source._vec);
}

void FieldSet::copy(const std::vector<Field>& definition)
{
	_vec = definition;

	//make fields map from vector
	for (int index = 0; index < (int)_vec.size(); index++)
	{
		Field& field = _vec[index];
		_map[field.getName()] = &field;
	}
}

int FieldSet::count()
{
	return (int)_vec.size();
}

Field* FieldSet::getByIndex(int index)
{
	if ((index >= 0) && (index < count()))
		return &_vec[index];

	return NULL;
}

Field* FieldSet::getByName(string name)
{
	return _map[name];
}

string FieldSet::getDefinition()
{
	string s;

	for (int index = 0; index < count(); index++)
	{
		if (Field* f = getByIndex(index))
		{
			s += f->getDefinition();
			if (index < (count() - 1))
				s += ", ";
		}
	}

	return s;
}

string FieldSet::definitionHash()
{
	string str = getDefinition();
	return generateSHA(str);
}

string FieldSet::toString()
{
	string s;

	for (int index = 0; index < count(); index++)
	{
		if (Field* f = getByIndex(index))
		{
			s += f->getName();
			if (index < (count() - 1))
				s += ", ";
		}
	}

	return s;
}

FieldSet* FieldSet::createFromDefinition(string value)
{
	std::vector<string> vec;
	listToVector(value, vec, ",");

	std::vector<Field> fields;

	for (int index = 0; index < (int)vec.size(); index++)
	{
		std::string definition = vec[index];

		if (Field* field = Field::createFromDefinition(definition))
		{
			Field f(*field);
			fields.push_back(f);
			delete field;
		} else {
			return NULL;
		}
	}

	return new FieldSet(fields);
}

//sql eof
};
<commit_msg>fix: fieldset copy func loss index set<commit_after>#include "SqlFieldSet.h"

namespace sql
{

FieldSet::FieldSet(Field* definition)
{
	//make fields map from array
	if (definition)
	{
		int index = 0;
		while (true)
		{
			Field& field = definition[index];

			if (field.isEndingField())
				break;

			field._index = index;

			_vec.push_back(field);
			_map[field.getName()] = &field;

			index++;
		}
	}
}

FieldSet::FieldSet(std::vector<Field>& definition)
{
	copy(definition);
}

FieldSet::FieldSet(const FieldSet& source)
{
	copy(source._vec);
}

void FieldSet::copy(const std::vector<Field>& definition)
{
	_vec = definition;

	//make fields map from vector
	for (int index = 0; index < (int)_vec.size(); index++)
	{
		Field& field = _vec[index];
		field._index = index;
		_map[field.getName()] = &field;
	}
}

int FieldSet::count()
{
	return (int)_vec.size();
}

Field* FieldSet::getByIndex(int index)
{
	if ((index >= 0) && (index < count()))
		return &_vec[index];

	return NULL;
}

Field* FieldSet::getByName(string name)
{
	return _map[name];
}

string FieldSet::getDefinition()
{
	string s;

	for (int index = 0; index < count(); index++)
	{
		if (Field* f = getByIndex(index))
		{
			s += f->getDefinition();
			if (index < (count() - 1))
				s += ", ";
		}
	}

	return s;
}

string FieldSet::definitionHash()
{
	string str = getDefinition();
	return generateSHA(str);
}

string FieldSet::toString()
{
	string s;

	for (int index = 0; index < count(); index++)
	{
		if (Field* f = getByIndex(index))
		{
			s += f->getName();
			if (index < (count() - 1))
				s += ", ";
		}
	}

	return s;
}

FieldSet* FieldSet::createFromDefinition(string value)
{
	std::vector<string> vec;
	listToVector(value, vec, ",");

	std::vector<Field> fields;

	for (int index = 0; index < (int)vec.size(); index++)
	{
		std::string definition = vec[index];

		if (Field* field = Field::createFromDefinition(definition))
		{
			Field f(*field);
			fields.push_back(f);
			delete field;
		} else {
			return NULL;
		}
	}

	return new FieldSet(fields);
}

//sql eof
};
<|endoftext|>


<commit_before>// Copyright (c) 2012 Cloudera, Inc. All rights reserved.

#include <vector>

#include <glog/logging.h>

#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/bind.hpp>
#include <boost/mem_fn.hpp>
#include <boost/foreach.hpp>

#include "runtime/coordinator.h"
#include "runtime/exec-env.h"

#include "sparrow/simple-scheduler.h"
#include "sparrow/state-store-subscriber-service.h"
#include "gen-cpp/Types_types.h"

using namespace std;
using namespace boost;
using impala::Status;
using impala::THostPort;
using impala::ExecEnv;

namespace sparrow {

SimpleScheduler::SimpleScheduler(SubscriptionManager* subscription_manager,
    const ServiceId& backend_service_id)
  : subscription_manager_(subscription_manager),
    callback_(bind<void>(mem_fn(&SimpleScheduler::UpdateMembership), this, _1)),
    subscription_id_(INVALID_SUBSCRIPTION_ID),
    backend_service_id_(backend_service_id) {
  next_nonlocal_host_entry_ = host_map_.begin();
}

SimpleScheduler::SimpleScheduler(const vector<THostPort>& backends)
  : subscription_manager_(NULL),
    callback_(NULL),
    subscription_id_(INVALID_SUBSCRIPTION_ID) {
  DCHECK(backends.size() > 0);
  for (int i = 0; i < backends.size(); ++i) {
    string host = backends[i].host;
    int port = backends[i].port;

    HostMap::iterator i = host_map_.find(host);
    if (i == host_map_.end()) {
      i = host_map_.insert(make_pair(host, list<int>())).first;
    }
    i->second.push_back(port);
  }
  next_nonlocal_host_entry_ = host_map_.begin();
}

SimpleScheduler::~SimpleScheduler() {
  DCHECK_EQ(subscription_id_, INVALID_SUBSCRIPTION_ID) << "Did not call Close()";
}

impala::Status SimpleScheduler::Init() {
  if (subscription_manager_ == NULL) return Status::OK;

  unordered_set<string> services;
  services.insert(backend_service_id_);
  RETURN_IF_ERROR(subscription_manager_->RegisterSubscription(
      services, &callback_, &subscription_id_));

  return Status::OK;
}

void SimpleScheduler::UpdateMembership(const ServiceStateMap& service_state) {
  lock_guard<mutex> lock(host_map_lock_);
  VLOG_ROW << "Received update from subscription manager" << endl;
  host_map_.clear();
  ServiceStateMap::const_iterator it = service_state.find(backend_service_id_);
  if (it != service_state.end()) {
    VLOG_ROW << "Found membership information for " << backend_service_id_;
    ServiceState service_state = it->second;
    BOOST_FOREACH(const Membership::value_type& member, service_state.membership) {
      VLOG_ROW << "Got member: " << member.second.host << ":" << member.second.port;
      HostMap::iterator host_it = host_map_.find(member.second.host);
      if (host_it == host_map_.end()) {
        host_it = host_map_.insert(make_pair(member.second.host, list<int>())).first;
      }
      host_it->second.push_back(member.second.port);
    }
  } else {
    VLOG_QUERY << "No membership information found.";
  }

  next_nonlocal_host_entry_ = host_map_.begin();
}

Status SimpleScheduler::GetHosts(
    const vector<THostPort>& data_locations, vector<pair<string, int> >* hostports) {
  lock_guard<mutex> lock(host_map_lock_);
  if (host_map_.size() == 0) {
    return Status("No backends configured");
  }
  hostports->clear();
  for (int i = 0; i < data_locations.size(); ++i) {
    HostMap::iterator entry = host_map_.find(data_locations[i].host);
    if (entry == host_map_.end()) {
      // round robin the host
      entry = next_nonlocal_host_entry_;
      ++next_nonlocal_host_entry_;
      if (next_nonlocal_host_entry_ == host_map_.end()) {
        next_nonlocal_host_entry_ = host_map_.begin();
      }
    }
    DCHECK(!entry->second.empty());
    // Round-robin between impalads on the same host. Pick the first one, then move it
    // to the back of the queue
    int port = entry->second.front();
    hostports->push_back(make_pair(entry->first, port));
    entry->second.pop_front();
    entry->second.push_back(port);
  }
  if (VLOG_QUERY_IS_ON) {
    vector<string> hostport_strings;
    for (int i = 0; i < hostports->size(); ++i) {
      stringstream s;
      s << (*hostports)[i].first << ":" << (*hostports)[i].second;
      hostport_strings.push_back(s.str());
    }
    VLOG_QUERY << "SimpleScheduler: selecting "
               << algorithm::join(hostport_strings, ", ");
  }
  DCHECK_EQ(data_locations.size(), hostports->size());
  return Status::OK;
}

void SimpleScheduler::GetAllKnownHosts(vector<pair<string, int> >* hostports) {
  lock_guard<mutex> lock(host_map_lock_);
  hostports->clear();
  BOOST_FOREACH(HostMap::value_type host, host_map_) {
    BOOST_FOREACH(int port, host.second) {
      hostports->push_back(make_pair(host.first, port));
    }
  }
}

void SimpleScheduler::Close() {
  if (subscription_manager_ != NULL && subscription_id_ != INVALID_SUBSCRIPTION_ID) {
    VLOG_QUERY << "Unregistering simple scheduler with subscription manager";
    Status status = subscription_manager_->UnregisterSubscription(subscription_id_);
    if (!status.ok()) {
      LOG(ERROR) << "Error unsubscribing from subscription manager: "
                 << status.GetErrorMsg();
    }
  }
  // Reset everything to make sure no one can use this anymore
  subscription_id_ = INVALID_SUBSCRIPTION_ID;
  subscription_manager_ = NULL;
  host_map_.clear();
}

}
<commit_msg>IMP-242: Log scheduler assignments and locality %-age<commit_after>// Copyright (c) 2012 Cloudera, Inc. All rights reserved.

#include <vector>

#include <glog/logging.h>

#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/bind.hpp>
#include <boost/mem_fn.hpp>
#include <boost/foreach.hpp>

#include "runtime/coordinator.h"
#include "runtime/exec-env.h"

#include "sparrow/simple-scheduler.h"
#include "sparrow/state-store-subscriber-service.h"
#include "gen-cpp/Types_types.h"

using namespace std;
using namespace boost;
using impala::Status;
using impala::THostPort;
using impala::ExecEnv;

namespace sparrow {

SimpleScheduler::SimpleScheduler(SubscriptionManager* subscription_manager,
    const ServiceId& backend_service_id)
  : subscription_manager_(subscription_manager),
    callback_(bind<void>(mem_fn(&SimpleScheduler::UpdateMembership), this, _1)),
    subscription_id_(INVALID_SUBSCRIPTION_ID),
    backend_service_id_(backend_service_id) {
  next_nonlocal_host_entry_ = host_map_.begin();
}

SimpleScheduler::SimpleScheduler(const vector<THostPort>& backends)
  : subscription_manager_(NULL),
    callback_(NULL),
    subscription_id_(INVALID_SUBSCRIPTION_ID) {
  DCHECK(backends.size() > 0);
  for (int i = 0; i < backends.size(); ++i) {
    string host = backends[i].host;
    int port = backends[i].port;

    HostMap::iterator i = host_map_.find(host);
    if (i == host_map_.end()) {
      i = host_map_.insert(make_pair(host, list<int>())).first;
    }
    i->second.push_back(port);
  }
  next_nonlocal_host_entry_ = host_map_.begin();
}

SimpleScheduler::~SimpleScheduler() {
  DCHECK_EQ(subscription_id_, INVALID_SUBSCRIPTION_ID) << "Did not call Close()";
}

impala::Status SimpleScheduler::Init() {
  if (subscription_manager_ == NULL) return Status::OK;

  unordered_set<string> services;
  services.insert(backend_service_id_);
  RETURN_IF_ERROR(subscription_manager_->RegisterSubscription(
      services, &callback_, &subscription_id_));

  return Status::OK;
}

void SimpleScheduler::UpdateMembership(const ServiceStateMap& service_state) {
  lock_guard<mutex> lock(host_map_lock_);
  VLOG_ROW << "Received update from subscription manager" << endl;
  host_map_.clear();
  ServiceStateMap::const_iterator it = service_state.find(backend_service_id_);
  if (it != service_state.end()) {
    VLOG_ROW << "Found membership information for " << backend_service_id_;
    ServiceState service_state = it->second;
    BOOST_FOREACH(const Membership::value_type& member, service_state.membership) {
      VLOG_ROW << "Got member: " << member.second.host << ":" << member.second.port;
      HostMap::iterator host_it = host_map_.find(member.second.host);
      if (host_it == host_map_.end()) {
        host_it = host_map_.insert(make_pair(member.second.host, list<int>())).first;
      }
      host_it->second.push_back(member.second.port);
    }
  } else {
    VLOG_QUERY << "No membership information found.";
  }

  next_nonlocal_host_entry_ = host_map_.begin();
}

Status SimpleScheduler::GetHosts(
    const vector<THostPort>& data_locations, vector<pair<string, int> >* hostports) {
  lock_guard<mutex> lock(host_map_lock_);
  if (host_map_.size() == 0) {
    return Status("No backends configured");
  }
  hostports->clear();
  int num_local_assignments = 0;
  for (int i = 0; i < data_locations.size(); ++i) {
    HostMap::iterator entry = host_map_.find(data_locations[i].host);
    if (entry == host_map_.end()) {
      // round robin the host
      entry = next_nonlocal_host_entry_;
      ++next_nonlocal_host_entry_;
      if (next_nonlocal_host_entry_ == host_map_.end()) {
        next_nonlocal_host_entry_ = host_map_.begin();
      }
    } else {
      ++num_local_assignments;
    }
    DCHECK(!entry->second.empty());
    // Round-robin between impalads on the same host. Pick the first one, then move it
    // to the back of the queue
    int port = entry->second.front();
    hostports->push_back(make_pair(entry->first, port));
    entry->second.pop_front();
    entry->second.push_back(port);
  }
  if (VLOG_QUERY_IS_ON) {
    vector<string> hostport_strings;
    for (int i = 0; i < hostports->size(); ++i) {
      stringstream s;
      s << "(" << data_locations[i].host << ":" << data_locations[i].port
        << " -> " << (*hostports)[i].first << ":" << (*hostports)[i].second << ")";
      hostport_strings.push_back(s.str());
    }
    VLOG_QUERY << "SimpleScheduler assignment (data->backend):  "
               << algorithm::join(hostport_strings, ", ");
    if (data_locations.size() > 0) {
      VLOG_QUERY << "SimpleScheduler locality percentage " << setprecision(4)
                 << 100.0f * (num_local_assignments / (float)data_locations.size())
                 << "% (" << num_local_assignments << " out of " << data_locations.size()
                 << ")";
    }
  }
  DCHECK_EQ(data_locations.size(), hostports->size());
  return Status::OK;
}

void SimpleScheduler::GetAllKnownHosts(vector<pair<string, int> >* hostports) {
  lock_guard<mutex> lock(host_map_lock_);
  hostports->clear();
  BOOST_FOREACH(HostMap::value_type host, host_map_) {
    BOOST_FOREACH(int port, host.second) {
      hostports->push_back(make_pair(host.first, port));
    }
  }
}

void SimpleScheduler::Close() {
  if (subscription_manager_ != NULL && subscription_id_ != INVALID_SUBSCRIPTION_ID) {
    VLOG_QUERY << "Unregistering simple scheduler with subscription manager";
    Status status = subscription_manager_->UnregisterSubscription(subscription_id_);
    if (!status.ok()) {
      LOG(ERROR) << "Error unsubscribing from subscription manager: "
                 << status.GetErrorMsg();
    }
  }
  // Reset everything to make sure no one can use this anymore
  subscription_id_ = INVALID_SUBSCRIPTION_ID;
  subscription_manager_ = NULL;
  host_map_.clear();
}

}
<|endoftext|>


<commit_before>//
// SRTerrain class : a subclass of vtDynTerrainGeom which encapsulates
//  Stefan Roettger's CLOD algorithm.
//
// utilizes: Roettger's MINI library implementation
// http://wwwvis.informatik.uni-stuttgart.de/~roettger
//
// Copyright (c) 2002-2004 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "SRTerrain.h"
#include "vtdata/vtLog.h"

#if VTLIB_NI
// stub
SRTerrain::SRTerrain() {}
SRTerrain::~SRTerrain() {}
float SRTerrain::GetElevation(int iX, int iZ, bool bTrue) const { return 0; }
void SRTerrain::GetWorldLocation(int i, int j, FPoint3 &p, bool bTrue) const {}
void SRTerrain::DoCulling(const vtCamera *pCam) {}
void SRTerrain::DoRender() {}
void SRTerrain::SetVerticalExag(float fExag) {}
DTErr SRTerrain::Init(const vtElevationGrid *pGrid, float fZScale) { return DTErr_NOMEM; }
#else

#include "mini.h"
#include "ministub.hpp"

using namespace mini;
#ifdef _MSC_VER
#pragma comment( lib, "libMini.lib" )
#endif

/////////////////////////////////////////////////////////////////////////////

float SRTerrain::s_fAdaptationSpeed = .0002f;		// speed at which detail converges

//
// Constructor/destructor
//
SRTerrain::SRTerrain() : vtDynTerrainGeom()
{
	m_fResolution = 10000.0f;
	m_pMini = NULL;
	m_iLastDiff = 0;
	m_fDamping = 0;
}

SRTerrain::~SRTerrain()
{
	if (m_pMini)
	{
		delete m_pMini;
		m_pMini = NULL;
	}
}

/////////////////////////////////////////////////////////////////////////////

//
// Unfortunately the following statics are required because libMini only
// supports some functionality by callback, and the callback is only a
// simple C function which has no context to tell us which terrain.
//
static const vtElevationGrid *s_pGrid;
static SRTerrain *s_pSRTerrain;
static int myfancnt, myvtxcnt;

void beginfan_vtp()
{
	if (myfancnt++>0)
		glEnd();
	glBegin(GL_TRIANGLE_FAN);
	myvtxcnt-=2;	// 2 vertices are needed to start each fan
}

void fanvertex_vtp(float x, float y, float z)
{
	glVertex3f(x,y,z);
	myvtxcnt++;
}

void notify_vtp(int i, int j, int size)
{
	// check to see if we need to switch texture
	if (s_pSRTerrain->m_iTPatchDim > 1 && size == s_pSRTerrain->m_iBlockSize)
	{
		int a = i / size;
		int b = j / size;
		s_pSRTerrain->LoadBlockMaterial(a, b);
	}
}

short int getelevation_vtp1(int i, int j, int size)
{
	return s_pGrid->GetValue(i, j);
}

float getelevation_vtp2(int i, int j, int size)
{
	return s_pGrid->GetFValue(i, j);
}

//
// Initialize the terrain data
// fZScale converts from height values (meters) to world coordinates
//
DTErr SRTerrain::Init(const vtElevationGrid *pGrid, float fZScale)
{
	// Initializes necessary field of the parent class
	DTErr err = BasicInit(pGrid);
	if (err != DTErr_OK)
		return err;

	if (m_iColumns != m_iRows)
		return DTErr_NOTSQUARE;

	// compute n (log2 of grid size)
	// ensure that the grid is size (1 << n) + 1
	int n = vt_log2(m_iColumns - 1);
	int required_size = (1<<n) + 1;
	if (m_iColumns != required_size || m_iRows != required_size)
		return DTErr_NOTPOWER2;

	int size = m_iColumns;
	float dim = m_fXStep;
	float cellaspect = m_fZStep / m_fXStep;

	s_pGrid = pGrid;

#if 0
	// NOTE: the following workaround is no longer needed with libMini 5.02
	//
	// Totally strange but repeatable behavior: runtime exit in Release-mode
	//  libMini with values over a certain level.  Workaround here!
	// Exit happens if (scale * maximum_height / dim > 967)
	//
	// 	scale * maximum_height / dim > 967
	//	scale > dim * 967 / maximum_height
	//
	float fMin, fMax;
	pGrid->GetHeightExtents(fMin, fMax);
	// Avoid trouble with fMax small or zero
	if (fMax < 10) fMax = 10;
	// compute the largest supported value for MaxScale
	float fMaxMax = dim * 960 / fMax;
	// values greater than 10 are unnecessarily large
	if (fMaxMax > 10)
		fMaxMax = 10;
	m_fMaximumScale = fMaxMax;
#else
	// This maxiumum scale is a reasonable tradeoff between the exaggeration
	//  that the user is likely to need, and numerical precision issues.
	m_fMaximumScale = 10;
#endif

	m_fHeightScale = fZScale;
	m_fDrawScale = m_fHeightScale / m_fMaximumScale;

	if (pGrid->IsFloatMode())
	{
		float *image = NULL;
		m_pMini = new ministub(image,
				&size, &dim, m_fMaximumScale, cellaspect,
				beginfan_vtp, fanvertex_vtp, notify_vtp,
				getelevation_vtp2);
	}
	else
	{
		short *image = NULL;
		m_pMini = new ministub(image,
				&size, &dim, m_fMaximumScale, cellaspect,
				beginfan_vtp, fanvertex_vtp, notify_vtp,
				getelevation_vtp1);
	}

	m_iDrawnTriangles = -1;
	m_iBlockSize = m_iColumns / 4;

	return DTErr_OK;
}

void SRTerrain::SetVerticalExag(float fExag)
{
	m_fHeightScale = fExag;

	// safety check
	if (m_fHeightScale > m_fMaximumScale)
		m_fHeightScale = m_fMaximumScale;

	m_fDrawScale = m_fHeightScale / m_fMaximumScale;
}

//
// This will be called once per frame, during the culling pass.
//
// However, libMini does not allow you to call the culling pass
// independently of the rendering pass, so we cannot do culling here.
// Instead, just store the values for later use.
//
void SRTerrain::DoCulling(const vtCamera *pCam)
{
	// Grab necessary values from the VTP Scene framework, store for later
	m_eyepos_ogl = pCam->GetTrans();
	m_window_size = vtGetScene()->GetWindowSize();
	m_fAspect = (float)m_window_size.x / m_window_size.y;
	m_fNear = pCam->GetHither();
	m_fFar = pCam->GetYon();

	// Get up vector and direction vector from camera matrix
	FMatrix4 mat;
	pCam->GetTransform1(mat);
	FPoint3 up(0.0f, 1.0f, 0.0f);
	mat.TransformVector(up, eye_up);

	FPoint3 forward(0.0f, 0.0f, -1.0f);
	mat.TransformVector(forward, eye_forward);

	if (pCam->IsOrtho())
	{
		// libMini supports orthographic viewing as of libMini 5.0.
		// A negative FOV value indicates to the library that the FOV is
		//  actually the orthographic height of the camera.
		m_fFOVY = pCam->GetWidth() / m_fAspect;
		m_fFOVY = -m_fFOVY;
	}
	else
	{
		float fov = pCam->GetFOV();
		float fov_y2 = atan(tan (fov/2) / m_fAspect);
		m_fFOVY = fov_y2 * 2.0f * 180 / PIf;
	}
}

void SRTerrain::DoRender()
{
	// Prepare the render state for our OpenGL usage
	PreRender();

	// Render the triangles
	RenderSurface();

	// Clean up
	PostRender();
}

void SRTerrain::LoadSingleMaterial()
{
	// single texture for the whole terrain
	vtMaterial *pMat = GetMaterial(0);
	if (pMat)
	{
		pMat->Apply();
		SetupTexGen(1.0f);
	}
}

void SRTerrain::LoadBlockMaterial(int a, int b)
{
	// we can't change the texture between glBegin/glEnd
	if (myfancnt++>0)
		glEnd();

	// each block has it's own texture map
	int matidx = a*m_iTPatchDim + (m_iTPatchDim-1-b);
	vtMaterial *pMat = GetMaterial(matidx);
	if (pMat)
	{
		pMat->Apply();
		SetupBlockTexGen(a, b);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	}

	glBegin(GL_TRIANGLE_FAN);
}

void SRTerrain::RenderSurface()
{
	s_pSRTerrain = this;

	if (m_iTPatchDim == 1)
		LoadSingleMaterial();

	RenderPass();

	// how to do a second rendering pass
	if (m_bDetailTexture)
	{
		// once again, with the detail texture material
		m_pDetailMat->Apply();

		// the uv tiling is different (usually highly repetitive)
		SetupTexGen(m_fDetailTiling);

		// draw the second pass
		glPolygonOffset(-1.0f, -1.0f);
		glEnable(GL_POLYGON_OFFSET_FILL);
		RenderPass();
		glDisable(GL_POLYGON_OFFSET_FILL);
	}
	DisableTexGen();
}

void SRTerrain::RenderPass()
{
	float ex = m_eyepos_ogl.x;
	float ey = m_eyepos_ogl.y;
	float ez = m_eyepos_ogl.z;

	float fov = m_fFOVY;

	float ux = eye_up.x;
	float uy = eye_up.y;
	float uz = eye_up.z;

	float dx = eye_forward.x;
	float dy = eye_forward.y;
	float dz = eye_forward.z;

	myfancnt = myvtxcnt = 0;

	// Convert the eye location to the unusual coordinate scheme of libMini.
	ex -= (m_iColumns/2)*m_fXStep;
	ez += (m_iRows/2)*m_fZStep;

	m_pMini->draw(m_fResolution,
				ex, ey, ez,
				dx, dy, dz,
				ux, uy, uz,
				fov, m_fAspect,
				m_fNear, m_fFar,
				m_fDrawScale);

	if (myfancnt>0) glEnd();

	// We are drawing fans, so the number of triangles is roughly equal to
	// number of vertices
	m_iDrawnTriangles = myvtxcnt;

	// adaptively adjust resolution threshold up or down to attain
	// the desired polygon (vertex) count target
	int diff = m_iDrawnTriangles - m_iPolygonTarget;
	int iRange = m_iPolygonTarget / 10;		// ensure within 10%
	float adjust = 1.0f;

	if (diff < -iRange || diff > iRange)
	{
		// the amount we change resolution is proportional to how much we
		//  missed our triangle count target
		float change_by = -diff * s_fAdaptationSpeed;

		// avoid hysteresis by using additional damping on direction change
		if ((m_iLastDiff > 0 && diff < 0) ||
			(m_iLastDiff < 0 && diff > 0))
		{
//			VTLOG("Changing dir, diff %d, previous %d\n", diff, previous_diff);
			m_fDamping = -0.9;	// 90% damping
		}
		change_by *= (1.0 + m_fDamping);

		// exponential response factor
		adjust = pow(2.0, (double)change_by);

		// clamp, to avoid extreme cases
		if (adjust > 100.0f) adjust = 100.0f;
		if (adjust < 0.01f) adjust = 0.01f;
	}
	m_iLastDiff = diff;	// remember for next frame
	m_fDamping /= 2;	// damping falls off rapidly

	m_fResolution *= adjust;

	// keep the error within reasonable bounds
	if (m_fResolution < 1.0f)
		m_fResolution = 1.0f;
	if (m_fResolution > 4E7)
		m_fResolution = 4E7;
}

//
// These methods are called when the framework needs to know the surface
// position of the terrain at a given grid point.  Supply the height
// value from our own data structures.
//
float SRTerrain::GetElevation(int iX, int iZ, bool bTrue) const
{
	float height = m_pMini->getheight(iX, iZ);

	if (bTrue)
		// convert stored value to true value
		return height / m_fMaximumScale;
	else
		// convert stored value to drawn value
		return height * m_fDrawScale;
}

void SRTerrain::GetWorldLocation(int i, int j, FPoint3 &p, bool bTrue) const
{
	float height = m_pMini->getheight(i, j);

	if (bTrue)
		// convert stored value to true value
		height /= m_fMaximumScale;
	else
		// convert stored value to drawn value
		height *= m_fDrawScale;

	p.Set(m_fXLookup[i],
		  height,
		  m_fZLookup[j]);
}

#endif	// VTLIB_NI
<commit_msg>yet another safety check on array bounds<commit_after>//
// SRTerrain class : a subclass of vtDynTerrainGeom which encapsulates
//  Stefan Roettger's CLOD algorithm.
//
// utilizes: Roettger's MINI library implementation
// http://wwwvis.informatik.uni-stuttgart.de/~roettger
//
// Copyright (c) 2002-2004 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include "SRTerrain.h"
#include "vtdata/vtLog.h"

#if VTLIB_NI
// stub
SRTerrain::SRTerrain() {}
SRTerrain::~SRTerrain() {}
float SRTerrain::GetElevation(int iX, int iZ, bool bTrue) const { return 0; }
void SRTerrain::GetWorldLocation(int i, int j, FPoint3 &p, bool bTrue) const {}
void SRTerrain::DoCulling(const vtCamera *pCam) {}
void SRTerrain::DoRender() {}
void SRTerrain::SetVerticalExag(float fExag) {}
DTErr SRTerrain::Init(const vtElevationGrid *pGrid, float fZScale) { return DTErr_NOMEM; }
#else

#include "mini.h"
#include "ministub.hpp"

using namespace mini;
#ifdef _MSC_VER
#pragma comment( lib, "libMini.lib" )
#endif

/////////////////////////////////////////////////////////////////////////////

float SRTerrain::s_fAdaptationSpeed = .0002f;		// speed at which detail converges

//
// Constructor/destructor
//
SRTerrain::SRTerrain() : vtDynTerrainGeom()
{
	m_fResolution = 10000.0f;
	m_pMini = NULL;
	m_iLastDiff = 0;
	m_fDamping = 0;
}

SRTerrain::~SRTerrain()
{
	if (m_pMini)
	{
		delete m_pMini;
		m_pMini = NULL;
	}
}

/////////////////////////////////////////////////////////////////////////////

//
// Unfortunately the following statics are required because libMini only
// supports some functionality by callback, and the callback is only a
// simple C function which has no context to tell us which terrain.
//
static const vtElevationGrid *s_pGrid;
static SRTerrain *s_pSRTerrain;
static int myfancnt, myvtxcnt;

void beginfan_vtp()
{
	if (myfancnt++>0)
		glEnd();
	glBegin(GL_TRIANGLE_FAN);
	myvtxcnt-=2;	// 2 vertices are needed to start each fan
}

void fanvertex_vtp(float x, float y, float z)
{
	glVertex3f(x,y,z);
	myvtxcnt++;
}

void notify_vtp(int i, int j, int size)
{
	// check to see if we need to switch texture
	if (s_pSRTerrain->m_iTPatchDim > 1 && size == s_pSRTerrain->m_iBlockSize)
	{
		int a = i / size;
		int b = j / size;
		s_pSRTerrain->LoadBlockMaterial(a, b);
	}
}

short int getelevation_vtp1(int i, int j, int size)
{
	return s_pGrid->GetValue(i, j);
}

float getelevation_vtp2(int i, int j, int size)
{
	return s_pGrid->GetFValue(i, j);
}

//
// Initialize the terrain data
// fZScale converts from height values (meters) to world coordinates
//
DTErr SRTerrain::Init(const vtElevationGrid *pGrid, float fZScale)
{
	// Initializes necessary field of the parent class
	DTErr err = BasicInit(pGrid);
	if (err != DTErr_OK)
		return err;

	if (m_iColumns != m_iRows)
		return DTErr_NOTSQUARE;

	// compute n (log2 of grid size)
	// ensure that the grid is size (1 << n) + 1
	int n = vt_log2(m_iColumns - 1);
	int required_size = (1<<n) + 1;
	if (m_iColumns != required_size || m_iRows != required_size)
		return DTErr_NOTPOWER2;

	int size = m_iColumns;
	float dim = m_fXStep;
	float cellaspect = m_fZStep / m_fXStep;

	s_pGrid = pGrid;

#if 0
	// NOTE: the following workaround is no longer needed with libMini 5.02
	//
	// Totally strange but repeatable behavior: runtime exit in Release-mode
	//  libMini with values over a certain level.  Workaround here!
	// Exit happens if (scale * maximum_height / dim > 967)
	//
	// 	scale * maximum_height / dim > 967
	//	scale > dim * 967 / maximum_height
	//
	float fMin, fMax;
	pGrid->GetHeightExtents(fMin, fMax);
	// Avoid trouble with fMax small or zero
	if (fMax < 10) fMax = 10;
	// compute the largest supported value for MaxScale
	float fMaxMax = dim * 960 / fMax;
	// values greater than 10 are unnecessarily large
	if (fMaxMax > 10)
		fMaxMax = 10;
	m_fMaximumScale = fMaxMax;
#else
	// This maxiumum scale is a reasonable tradeoff between the exaggeration
	//  that the user is likely to need, and numerical precision issues.
	m_fMaximumScale = 10;
#endif

	m_fHeightScale = fZScale;
	m_fDrawScale = m_fHeightScale / m_fMaximumScale;

	if (pGrid->IsFloatMode())
	{
		float *image = NULL;
		m_pMini = new ministub(image,
				&size, &dim, m_fMaximumScale, cellaspect,
				beginfan_vtp, fanvertex_vtp, notify_vtp,
				getelevation_vtp2);
	}
	else
	{
		short *image = NULL;
		m_pMini = new ministub(image,
				&size, &dim, m_fMaximumScale, cellaspect,
				beginfan_vtp, fanvertex_vtp, notify_vtp,
				getelevation_vtp1);
	}

	m_iDrawnTriangles = -1;
	m_iBlockSize = m_iColumns / 4;

	return DTErr_OK;
}

void SRTerrain::SetVerticalExag(float fExag)
{
	m_fHeightScale = fExag;

	// safety check
	if (m_fHeightScale > m_fMaximumScale)
		m_fHeightScale = m_fMaximumScale;

	m_fDrawScale = m_fHeightScale / m_fMaximumScale;
}

//
// This will be called once per frame, during the culling pass.
//
// However, libMini does not allow you to call the culling pass
// independently of the rendering pass, so we cannot do culling here.
// Instead, just store the values for later use.
//
void SRTerrain::DoCulling(const vtCamera *pCam)
{
	// Grab necessary values from the VTP Scene framework, store for later
	m_eyepos_ogl = pCam->GetTrans();
	m_window_size = vtGetScene()->GetWindowSize();
	m_fAspect = (float)m_window_size.x / m_window_size.y;
	m_fNear = pCam->GetHither();
	m_fFar = pCam->GetYon();

	// Get up vector and direction vector from camera matrix
	FMatrix4 mat;
	pCam->GetTransform1(mat);
	FPoint3 up(0.0f, 1.0f, 0.0f);
	mat.TransformVector(up, eye_up);

	FPoint3 forward(0.0f, 0.0f, -1.0f);
	mat.TransformVector(forward, eye_forward);

	if (pCam->IsOrtho())
	{
		// libMini supports orthographic viewing as of libMini 5.0.
		// A negative FOV value indicates to the library that the FOV is
		//  actually the orthographic height of the camera.
		m_fFOVY = pCam->GetWidth() / m_fAspect;
		m_fFOVY = -m_fFOVY;
	}
	else
	{
		float fov = pCam->GetFOV();
		float fov_y2 = atan(tan (fov/2) / m_fAspect);
		m_fFOVY = fov_y2 * 2.0f * 180 / PIf;
	}
}

void SRTerrain::DoRender()
{
	// Prepare the render state for our OpenGL usage
	PreRender();

	// Render the triangles
	RenderSurface();

	// Clean up
	PostRender();
}

void SRTerrain::LoadSingleMaterial()
{
	// single texture for the whole terrain
	vtMaterial *pMat = GetMaterial(0);
	if (pMat)
	{
		pMat->Apply();
		SetupTexGen(1.0f);
	}
}

void SRTerrain::LoadBlockMaterial(int a, int b)
{
	// we can't change the texture between glBegin/glEnd
	if (myfancnt++>0)
		glEnd();

	// each block has it's own texture map
	int matidx = a*m_iTPatchDim + (m_iTPatchDim-1-b);
	vtMaterial *pMat = GetMaterial(matidx);
	if (pMat)
	{
		pMat->Apply();
		SetupBlockTexGen(a, b);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	}

	glBegin(GL_TRIANGLE_FAN);
}

void SRTerrain::RenderSurface()
{
	s_pSRTerrain = this;

	if (m_iTPatchDim == 1)
		LoadSingleMaterial();

	RenderPass();

	// how to do a second rendering pass
	if (m_bDetailTexture)
	{
		// once again, with the detail texture material
		m_pDetailMat->Apply();

		// the uv tiling is different (usually highly repetitive)
		SetupTexGen(m_fDetailTiling);

		// draw the second pass
		glPolygonOffset(-1.0f, -1.0f);
		glEnable(GL_POLYGON_OFFSET_FILL);
		RenderPass();
		glDisable(GL_POLYGON_OFFSET_FILL);
	}
	DisableTexGen();
}

void SRTerrain::RenderPass()
{
	float ex = m_eyepos_ogl.x;
	float ey = m_eyepos_ogl.y;
	float ez = m_eyepos_ogl.z;

	float fov = m_fFOVY;

	float ux = eye_up.x;
	float uy = eye_up.y;
	float uz = eye_up.z;

	float dx = eye_forward.x;
	float dy = eye_forward.y;
	float dz = eye_forward.z;

	myfancnt = myvtxcnt = 0;

	// Convert the eye location to the unusual coordinate scheme of libMini.
	ex -= (m_iColumns/2)*m_fXStep;
	ez += (m_iRows/2)*m_fZStep;

	m_pMini->draw(m_fResolution,
				ex, ey, ez,
				dx, dy, dz,
				ux, uy, uz,
				fov, m_fAspect,
				m_fNear, m_fFar,
				m_fDrawScale);

	if (myfancnt>0) glEnd();

	// We are drawing fans, so the number of triangles is roughly equal to
	// number of vertices
	m_iDrawnTriangles = myvtxcnt;

	// adaptively adjust resolution threshold up or down to attain
	// the desired polygon (vertex) count target
	int diff = m_iDrawnTriangles - m_iPolygonTarget;
	int iRange = m_iPolygonTarget / 10;		// ensure within 10%
	float adjust = 1.0f;

	if (diff < -iRange || diff > iRange)
	{
		// the amount we change resolution is proportional to how much we
		//  missed our triangle count target
		float change_by = -diff * s_fAdaptationSpeed;

		// avoid hysteresis by using additional damping on direction change
		if ((m_iLastDiff > 0 && diff < 0) ||
			(m_iLastDiff < 0 && diff > 0))
		{
//			VTLOG("Changing dir, diff %d, previous %d\n", diff, previous_diff);
			m_fDamping = -0.9;	// 90% damping
		}
		change_by *= (1.0 + m_fDamping);

		// exponential response factor
		adjust = pow(2.0, (double)change_by);

		// clamp, to avoid extreme cases
		if (adjust > 100.0f) adjust = 100.0f;
		if (adjust < 0.01f) adjust = 0.01f;
	}
	m_iLastDiff = diff;	// remember for next frame
	m_fDamping /= 2;	// damping falls off rapidly

	m_fResolution *= adjust;

	// keep the error within reasonable bounds
	if (m_fResolution < 1.0f)
		m_fResolution = 1.0f;
	if (m_fResolution > 4E7)
		m_fResolution = 4E7;
}

//
// These methods are called when the framework needs to know the surface
// position of the terrain at a given grid point.  Supply the height
// value from our own data structures.
//
float SRTerrain::GetElevation(int iX, int iZ, bool bTrue) const
{
	float height = m_pMini->getheight(iX, iZ);

	if (iX<0 || iX>m_iColumns-1 || iZ<0 || iZ>m_iRows-1)
		return 0.0f;

	if (bTrue)
		// convert stored value to true value
		return height / m_fMaximumScale;
	else
		// convert stored value to drawn value
		return height * m_fDrawScale;
}

void SRTerrain::GetWorldLocation(int i, int j, FPoint3 &p, bool bTrue) const
{
	float height = m_pMini->getheight(i, j);

	if (bTrue)
		// convert stored value to true value
		height /= m_fMaximumScale;
	else
		// convert stored value to drawn value
		height *= m_fDrawScale;

	p.Set(m_fXLookup[i],
		  height,
		  m_fZLookup[j]);
}

#endif	// VTLIB_NI
<|endoftext|>


<commit_before>//===- DeadStoreElimination.cpp - Fast Dead Store Elimination -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Owen Anderson and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a trivial dead store elimination that only considers
// basic-block local redundant stores.
//
// FIXME: This should eventually be extended to be a post-dominator tree
// traversal.  Doing so would be pretty trivial.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "dse"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Pass.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/MemoryDependenceAnalysis.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Support/Compiler.h"
using namespace llvm;

STATISTIC(NumFastStores, "Number of stores deleted");
STATISTIC(NumFastOther , "Number of other instrs removed");

namespace {
  struct VISIBILITY_HIDDEN DSE : public FunctionPass {
    static char ID; // Pass identification, replacement for typeid
    DSE() : FunctionPass((intptr_t)&ID) {}

    virtual bool runOnFunction(Function &F) {
      bool Changed = false;
      for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I)
        Changed |= runOnBasicBlock(*I);
      return Changed;
    }

    bool runOnBasicBlock(BasicBlock &BB);
    bool handleFreeWithNonTrivialDependency(FreeInst* F,
                                            Instruction* dependency,
                                        SetVector<Instruction*>& possiblyDead);
    bool handleEndBlock(BasicBlock& BB, SetVector<Instruction*>& possiblyDead);
    bool RemoveUndeadPointers(Value* pointer,
                              BasicBlock::iterator& BBI,
                              SmallPtrSet<AllocaInst*, 64>& deadPointers,
                              SetVector<Instruction*>& possiblyDead);
    void DeleteDeadInstructionChains(Instruction *I,
                                     SetVector<Instruction*> &DeadInsts);

    /// Find the base pointer that a pointer came from
    /// Because this is used to find pointers that originate
    /// from allocas, it is safe to ignore GEP indices, since
    /// either the store will be in the alloca, and thus dead,
    /// or beyond the end of the alloca, and thus undefined.
    void TranslatePointerBitCasts(Value*& v) {
      assert(isa<PointerType>(v->getType()) &&
             "Translating a non-pointer type?");
      while (true) {
        if (BitCastInst* C = dyn_cast<BitCastInst>(v))
          v = C->getOperand(0);
        else if (GetElementPtrInst* G = dyn_cast<GetElementPtrInst>(v))
          v = G->getOperand(0);
        else
          break;
      }
    }

    // getAnalysisUsage - We require post dominance frontiers (aka Control
    // Dependence Graph)
    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      AU.addRequired<TargetData>();
      AU.addRequired<AliasAnalysis>();
      AU.addRequired<MemoryDependenceAnalysis>();
      AU.addPreserved<AliasAnalysis>();
      AU.addPreserved<MemoryDependenceAnalysis>();
    }
  };
  char DSE::ID = 0;
  RegisterPass<DSE> X("dse", "Dead Store Elimination");
}

FunctionPass *llvm::createDeadStoreEliminationPass() { return new DSE(); }

bool DSE::runOnBasicBlock(BasicBlock &BB) {
  MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();

  // Record the last-seen store to this pointer
  DenseMap<Value*, StoreInst*> lastStore;
  // Record instructions possibly made dead by deleting a store
  SetVector<Instruction*> possiblyDead;

  bool MadeChange = false;

  // Do a top-down walk on the BB
  for (BasicBlock::iterator BBI = BB.begin(), BBE = BB.end();
       BBI != BBE; ++BBI) {
    // If we find a store or a free...
    if (!isa<StoreInst>(BBI) && !isa<FreeInst>(BBI))
      continue;

    Value* pointer = 0;
    if (StoreInst* S = dyn_cast<StoreInst>(BBI))
      pointer = S->getPointerOperand();
    else
      pointer = cast<FreeInst>(BBI)->getPointerOperand();

    StoreInst*& last = lastStore[pointer];
    bool deletedStore = false;

    // ... to a pointer that has been stored to before...
    if (last) {
      Instruction* dep = MD.getDependency(BBI);

      // ... and no other memory dependencies are between them....
      while (dep != MemoryDependenceAnalysis::None &&
             dep != MemoryDependenceAnalysis::NonLocal &&
             isa<StoreInst>(dep)) {
        if (dep != last) {
          dep = MD.getDependency(BBI, dep);
          continue;
        }

        // Remove it!
        MD.removeInstruction(last);

        // DCE instructions only used to calculate that store
        if (Instruction* D = dyn_cast<Instruction>(last->getOperand(0)))
          possiblyDead.insert(D);
        if (Instruction* D = dyn_cast<Instruction>(last->getOperand(1)))
          possiblyDead.insert(D);

        last->eraseFromParent();
        NumFastStores++;
        deletedStore = true;
        MadeChange = true;

        break;
      }
    }

    // Handle frees whose dependencies are non-trivial.
    if (FreeInst* F = dyn_cast<FreeInst>(BBI)) {
      if (!deletedStore)
        MadeChange |= handleFreeWithNonTrivialDependency(F,
                                                         MD.getDependency(F),
                                                         possiblyDead);
      // No known stores after the free
      last = 0;
    } else {
      // Update our most-recent-store map.
      last = cast<StoreInst>(BBI);
    }
  }

  // If this block ends in a return, unwind, unreachable, and eventually
  // tailcall, then all allocas are dead at its end.
  if (BB.getTerminator()->getNumSuccessors() == 0)
    MadeChange |= handleEndBlock(BB, possiblyDead);

  // Do a trivial DCE
  while (!possiblyDead.empty()) {
    Instruction *I = possiblyDead.back();
    possiblyDead.pop_back();
    DeleteDeadInstructionChains(I, possiblyDead);
  }

  return MadeChange;
}

/// handleFreeWithNonTrivialDependency - Handle frees of entire structures whose
/// dependency is a store to a field of that structure
bool DSE::handleFreeWithNonTrivialDependency(FreeInst* F, Instruction* dep,
                                       SetVector<Instruction*>& possiblyDead) {
  TargetData &TD = getAnalysis<TargetData>();
  AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
  MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();

  if (dep == MemoryDependenceAnalysis::None ||
      dep == MemoryDependenceAnalysis::NonLocal)
    return false;

  StoreInst* dependency = dyn_cast<StoreInst>(dep);
  if (!dependency)
    return false;

  Value* depPointer = dependency->getPointerOperand();
  const Type* depType = dependency->getOperand(0)->getType();
  unsigned depPointerSize = TD.getTypeSize(depType);

  // Check for aliasing
  AliasAnalysis::AliasResult A = AA.alias(F->getPointerOperand(), ~0UL,
                                          depPointer, depPointerSize);

  if (A == AliasAnalysis::MustAlias) {
    // Remove it!
    MD.removeInstruction(dependency);

    // DCE instructions only used to calculate that store
    if (Instruction* D = dyn_cast<Instruction>(dependency->getOperand(0)))
      possiblyDead.insert(D);
    if (Instruction* D = dyn_cast<Instruction>(dependency->getOperand(1)))
      possiblyDead.insert(D);

    dependency->eraseFromParent();
    NumFastStores++;
    return true;
  }

  return false;
}

/// handleEndBlock - Remove dead stores to stack-allocated locations in the
/// function end block.  Ex:
/// %A = alloca i32
/// ...
/// store i32 1, i32* %A
/// ret void
bool DSE::handleEndBlock(BasicBlock& BB,
                         SetVector<Instruction*>& possiblyDead) {
  TargetData &TD = getAnalysis<TargetData>();
  AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
  MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();

  bool MadeChange = false;

  // Pointers alloca'd in this function are dead in the end block
  SmallPtrSet<AllocaInst*, 64> deadPointers;

  // Find all of the alloca'd pointers in the entry block
  BasicBlock *Entry = BB.getParent()->begin();
  for (BasicBlock::iterator I = Entry->begin(), E = Entry->end(); I != E; ++I)
    if (AllocaInst *AI = dyn_cast<AllocaInst>(I))
      deadPointers.insert(AI);

  // Scan the basic block backwards
  for (BasicBlock::iterator BBI = BB.end(); BBI != BB.begin(); ){
    --BBI;

    if (deadPointers.empty())
      break;

    // If we find a store whose pointer is dead...
    if (StoreInst* S = dyn_cast<StoreInst>(BBI)) {
      Value* pointerOperand = S->getPointerOperand();
      // See through pointer-to-pointer bitcasts
      TranslatePointerBitCasts(pointerOperand);

      if (deadPointers.count(pointerOperand)){
        // Remove it!
        MD.removeInstruction(S);

        // DCE instructions only used to calculate that store
        if (Instruction* D = dyn_cast<Instruction>(S->getOperand(0)))
          possiblyDead.insert(D);
        if (Instruction* D = dyn_cast<Instruction>(S->getOperand(1)))
          possiblyDead.insert(D);

        BBI++;
        S->eraseFromParent();
        NumFastStores++;
        MadeChange = true;
      }

      continue;
    }

    Value* killPointer = 0;

    // If we encounter a use of the pointer, it is no longer considered dead
    if (LoadInst* L = dyn_cast<LoadInst>(BBI)) {
      killPointer = L->getPointerOperand();
    } else if (VAArgInst* V = dyn_cast<VAArgInst>(BBI)) {
      killPointer = V->getOperand(0);
    } else if (AllocaInst* A = dyn_cast<AllocaInst>(BBI)) {
      deadPointers.erase(A);
      continue;
    } else if (CallSite::get(BBI).getInstruction() != 0) {
      // Remove any pointers made undead by the call from the dead set
      std::vector<Instruction*> dead;
      for (SmallPtrSet<AllocaInst*, 64>::iterator I = deadPointers.begin(),
           E = deadPointers.end(); I != E; ++I) {
        // Get size information for the alloca
        unsigned pointerSize = ~0UL;
        if (ConstantInt* C = dyn_cast<ConstantInt>((*I)->getArraySize()))
          pointerSize = C->getZExtValue() * \
                        TD.getTypeSize((*I)->getAllocatedType());

        // See if the call site touches it
        AliasAnalysis::ModRefResult A = AA.getModRefInfo(CallSite::get(BBI),
                                                         *I, pointerSize);
        if (A == AliasAnalysis::ModRef || A == AliasAnalysis::Ref)
          dead.push_back(*I);
      }

      for (std::vector<Instruction*>::iterator I = dead.begin(), E = dead.end();
           I != E; ++I)
        deadPointers.erase(*I);

      continue;
    }

    if (!killPointer)
      continue;

    // Deal with undead pointers
    MadeChange |= RemoveUndeadPointers(killPointer, BBI,
                                       deadPointers, possiblyDead);
  }

  return MadeChange;
}

/// RemoveUndeadPointers - takes an instruction and a setvector of
/// dead instructions.  If I is dead, it is erased, and its operands are
/// checked for deadness.  If they are dead, they are added to the dead
/// setvector.
bool DSE::RemoveUndeadPointers(Value* killPointer,
                                BasicBlock::iterator& BBI,
                                SmallPtrSet<AllocaInst*, 64>& deadPointers,
                                SetVector<Instruction*>& possiblyDead) {
  TargetData &TD = getAnalysis<TargetData>();
  AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
  MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();

  bool MadeChange = false;

  std::vector<Instruction*> undead;

  for (SmallPtrSet<AllocaInst*, 64>::iterator I = deadPointers.begin(),
      E = deadPointers.end(); I != E; ++I) {
    // Get size information for the alloca
    unsigned pointerSize = ~0UL;
    if (ConstantInt* C = dyn_cast<ConstantInt>((*I)->getArraySize()))
      pointerSize = C->getZExtValue() * \
                    TD.getTypeSize((*I)->getAllocatedType());

    // See if this pointer could alias it
    AliasAnalysis::AliasResult A = AA.alias(*I, pointerSize,
                                            killPointer, ~0UL);

    // If it must-alias and a store, we can delete it
    if (isa<StoreInst>(BBI) && A == AliasAnalysis::MustAlias) {
      StoreInst* S = cast<StoreInst>(BBI);

      // Remove it!
      MD.removeInstruction(S);

      // DCE instructions only used to calculate that store
      if (Instruction* D = dyn_cast<Instruction>(S->getOperand(0)))
        possiblyDead.insert(D);
      if (Instruction* D = dyn_cast<Instruction>(S->getOperand(1)))
        possiblyDead.insert(D);

      BBI++;
      S->eraseFromParent();
      NumFastStores++;
      MadeChange = true;

      continue;

      // Otherwise, it is undead
      } else if (A != AliasAnalysis::NoAlias)
        undead.push_back(*I);
  }

  for (std::vector<Instruction*>::iterator I = undead.begin(), E = undead.end();
       I != E; ++I)
    deadPointers.erase(*I);

  return MadeChange;
}

/// DeleteDeadInstructionChains - takes an instruction and a setvector of
/// dead instructions.  If I is dead, it is erased, and its operands are
/// checked for deadness.  If they are dead, they are added to the dead
/// setvector.
void DSE::DeleteDeadInstructionChains(Instruction *I,
                                      SetVector<Instruction*> &DeadInsts) {
  // Instruction must be dead.
  if (!I->use_empty() || !isInstructionTriviallyDead(I)) return;

  // Let the memory dependence know
  getAnalysis<MemoryDependenceAnalysis>().removeInstruction(I);

  // See if this made any operands dead.  We do it this way in case the
  // instruction uses the same operand twice.  We don't want to delete a
  // value then reference it.
  for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) {
    if (I->getOperand(i)->hasOneUse())
      if (Instruction* Op = dyn_cast<Instruction>(I->getOperand(i)))
        DeadInsts.insert(Op);      // Attempt to nuke it later.

    I->setOperand(i, 0);         // Drop from the operand list.
  }

  I->eraseFromParent();
  ++NumFastOther;
}
<commit_msg>Small improvement: if a function doesn't access memory, we don't need to scan it for potentially undeading pointers.<commit_after>//===- DeadStoreElimination.cpp - Fast Dead Store Elimination -------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Owen Anderson and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a trivial dead store elimination that only considers
// basic-block local redundant stores.
//
// FIXME: This should eventually be extended to be a post-dominator tree
// traversal.  Doing so would be pretty trivial.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "dse"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Constants.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Pass.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/MemoryDependenceAnalysis.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Support/Compiler.h"
using namespace llvm;

STATISTIC(NumFastStores, "Number of stores deleted");
STATISTIC(NumFastOther , "Number of other instrs removed");

namespace {
  struct VISIBILITY_HIDDEN DSE : public FunctionPass {
    static char ID; // Pass identification, replacement for typeid
    DSE() : FunctionPass((intptr_t)&ID) {}

    virtual bool runOnFunction(Function &F) {
      bool Changed = false;
      for (Function::iterator I = F.begin(), E = F.end(); I != E; ++I)
        Changed |= runOnBasicBlock(*I);
      return Changed;
    }

    bool runOnBasicBlock(BasicBlock &BB);
    bool handleFreeWithNonTrivialDependency(FreeInst* F,
                                            Instruction* dependency,
                                        SetVector<Instruction*>& possiblyDead);
    bool handleEndBlock(BasicBlock& BB, SetVector<Instruction*>& possiblyDead);
    bool RemoveUndeadPointers(Value* pointer,
                              BasicBlock::iterator& BBI,
                              SmallPtrSet<AllocaInst*, 64>& deadPointers,
                              SetVector<Instruction*>& possiblyDead);
    void DeleteDeadInstructionChains(Instruction *I,
                                     SetVector<Instruction*> &DeadInsts);

    /// Find the base pointer that a pointer came from
    /// Because this is used to find pointers that originate
    /// from allocas, it is safe to ignore GEP indices, since
    /// either the store will be in the alloca, and thus dead,
    /// or beyond the end of the alloca, and thus undefined.
    void TranslatePointerBitCasts(Value*& v) {
      assert(isa<PointerType>(v->getType()) &&
             "Translating a non-pointer type?");
      while (true) {
        if (BitCastInst* C = dyn_cast<BitCastInst>(v))
          v = C->getOperand(0);
        else if (GetElementPtrInst* G = dyn_cast<GetElementPtrInst>(v))
          v = G->getOperand(0);
        else
          break;
      }
    }

    // getAnalysisUsage - We require post dominance frontiers (aka Control
    // Dependence Graph)
    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.setPreservesCFG();
      AU.addRequired<TargetData>();
      AU.addRequired<AliasAnalysis>();
      AU.addRequired<MemoryDependenceAnalysis>();
      AU.addPreserved<AliasAnalysis>();
      AU.addPreserved<MemoryDependenceAnalysis>();
    }
  };
  char DSE::ID = 0;
  RegisterPass<DSE> X("dse", "Dead Store Elimination");
}

FunctionPass *llvm::createDeadStoreEliminationPass() { return new DSE(); }

bool DSE::runOnBasicBlock(BasicBlock &BB) {
  MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();

  // Record the last-seen store to this pointer
  DenseMap<Value*, StoreInst*> lastStore;
  // Record instructions possibly made dead by deleting a store
  SetVector<Instruction*> possiblyDead;

  bool MadeChange = false;

  // Do a top-down walk on the BB
  for (BasicBlock::iterator BBI = BB.begin(), BBE = BB.end();
       BBI != BBE; ++BBI) {
    // If we find a store or a free...
    if (!isa<StoreInst>(BBI) && !isa<FreeInst>(BBI))
      continue;

    Value* pointer = 0;
    if (StoreInst* S = dyn_cast<StoreInst>(BBI))
      pointer = S->getPointerOperand();
    else
      pointer = cast<FreeInst>(BBI)->getPointerOperand();

    StoreInst*& last = lastStore[pointer];
    bool deletedStore = false;

    // ... to a pointer that has been stored to before...
    if (last) {
      Instruction* dep = MD.getDependency(BBI);

      // ... and no other memory dependencies are between them....
      while (dep != MemoryDependenceAnalysis::None &&
             dep != MemoryDependenceAnalysis::NonLocal &&
             isa<StoreInst>(dep)) {
        if (dep != last) {
          dep = MD.getDependency(BBI, dep);
          continue;
        }

        // Remove it!
        MD.removeInstruction(last);

        // DCE instructions only used to calculate that store
        if (Instruction* D = dyn_cast<Instruction>(last->getOperand(0)))
          possiblyDead.insert(D);
        if (Instruction* D = dyn_cast<Instruction>(last->getOperand(1)))
          possiblyDead.insert(D);

        last->eraseFromParent();
        NumFastStores++;
        deletedStore = true;
        MadeChange = true;

        break;
      }
    }

    // Handle frees whose dependencies are non-trivial.
    if (FreeInst* F = dyn_cast<FreeInst>(BBI)) {
      if (!deletedStore)
        MadeChange |= handleFreeWithNonTrivialDependency(F,
                                                         MD.getDependency(F),
                                                         possiblyDead);
      // No known stores after the free
      last = 0;
    } else {
      // Update our most-recent-store map.
      last = cast<StoreInst>(BBI);
    }
  }

  // If this block ends in a return, unwind, unreachable, and eventually
  // tailcall, then all allocas are dead at its end.
  if (BB.getTerminator()->getNumSuccessors() == 0)
    MadeChange |= handleEndBlock(BB, possiblyDead);

  // Do a trivial DCE
  while (!possiblyDead.empty()) {
    Instruction *I = possiblyDead.back();
    possiblyDead.pop_back();
    DeleteDeadInstructionChains(I, possiblyDead);
  }

  return MadeChange;
}

/// handleFreeWithNonTrivialDependency - Handle frees of entire structures whose
/// dependency is a store to a field of that structure
bool DSE::handleFreeWithNonTrivialDependency(FreeInst* F, Instruction* dep,
                                       SetVector<Instruction*>& possiblyDead) {
  TargetData &TD = getAnalysis<TargetData>();
  AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
  MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();

  if (dep == MemoryDependenceAnalysis::None ||
      dep == MemoryDependenceAnalysis::NonLocal)
    return false;

  StoreInst* dependency = dyn_cast<StoreInst>(dep);
  if (!dependency)
    return false;

  Value* depPointer = dependency->getPointerOperand();
  const Type* depType = dependency->getOperand(0)->getType();
  unsigned depPointerSize = TD.getTypeSize(depType);

  // Check for aliasing
  AliasAnalysis::AliasResult A = AA.alias(F->getPointerOperand(), ~0UL,
                                          depPointer, depPointerSize);

  if (A == AliasAnalysis::MustAlias) {
    // Remove it!
    MD.removeInstruction(dependency);

    // DCE instructions only used to calculate that store
    if (Instruction* D = dyn_cast<Instruction>(dependency->getOperand(0)))
      possiblyDead.insert(D);
    if (Instruction* D = dyn_cast<Instruction>(dependency->getOperand(1)))
      possiblyDead.insert(D);

    dependency->eraseFromParent();
    NumFastStores++;
    return true;
  }

  return false;
}

/// handleEndBlock - Remove dead stores to stack-allocated locations in the
/// function end block.  Ex:
/// %A = alloca i32
/// ...
/// store i32 1, i32* %A
/// ret void
bool DSE::handleEndBlock(BasicBlock& BB,
                         SetVector<Instruction*>& possiblyDead) {
  TargetData &TD = getAnalysis<TargetData>();
  AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
  MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();

  bool MadeChange = false;

  // Pointers alloca'd in this function are dead in the end block
  SmallPtrSet<AllocaInst*, 64> deadPointers;

  // Find all of the alloca'd pointers in the entry block
  BasicBlock *Entry = BB.getParent()->begin();
  for (BasicBlock::iterator I = Entry->begin(), E = Entry->end(); I != E; ++I)
    if (AllocaInst *AI = dyn_cast<AllocaInst>(I))
      deadPointers.insert(AI);

  // Scan the basic block backwards
  for (BasicBlock::iterator BBI = BB.end(); BBI != BB.begin(); ){
    --BBI;

    if (deadPointers.empty())
      break;

    // If we find a store whose pointer is dead...
    if (StoreInst* S = dyn_cast<StoreInst>(BBI)) {
      Value* pointerOperand = S->getPointerOperand();
      // See through pointer-to-pointer bitcasts
      TranslatePointerBitCasts(pointerOperand);

      if (deadPointers.count(pointerOperand)){
        // Remove it!
        MD.removeInstruction(S);

        // DCE instructions only used to calculate that store
        if (Instruction* D = dyn_cast<Instruction>(S->getOperand(0)))
          possiblyDead.insert(D);
        if (Instruction* D = dyn_cast<Instruction>(S->getOperand(1)))
          possiblyDead.insert(D);

        BBI++;
        S->eraseFromParent();
        NumFastStores++;
        MadeChange = true;
      }

      continue;
    }

    Value* killPointer = 0;

    // If we encounter a use of the pointer, it is no longer considered dead
    if (LoadInst* L = dyn_cast<LoadInst>(BBI)) {
      killPointer = L->getPointerOperand();
    } else if (VAArgInst* V = dyn_cast<VAArgInst>(BBI)) {
      killPointer = V->getOperand(0);
    } else if (AllocaInst* A = dyn_cast<AllocaInst>(BBI)) {
      deadPointers.erase(A);
      continue;
    } else if (CallSite::get(BBI).getInstruction() != 0) {
      // If this call does not access memory, it can't
      // be undeadifying any of our pointers.
      CallSite CS = CallSite::get(BBI);
      if (CS.getCalledFunction() &&
          AA.doesNotAccessMemory(CS.getCalledFunction()))
        continue;

      // Remove any pointers made undead by the call from the dead set
      std::vector<Instruction*> dead;
      for (SmallPtrSet<AllocaInst*, 64>::iterator I = deadPointers.begin(),
           E = deadPointers.end(); I != E; ++I) {
        // Get size information for the alloca
        unsigned pointerSize = ~0UL;
        if (ConstantInt* C = dyn_cast<ConstantInt>((*I)->getArraySize()))
          pointerSize = C->getZExtValue() * \
                        TD.getTypeSize((*I)->getAllocatedType());

        // See if the call site touches it
        AliasAnalysis::ModRefResult A = AA.getModRefInfo(CS, *I, pointerSize);
        if (A == AliasAnalysis::ModRef || A == AliasAnalysis::Ref)
          dead.push_back(*I);
      }

      for (std::vector<Instruction*>::iterator I = dead.begin(), E = dead.end();
           I != E; ++I)
        deadPointers.erase(*I);

      continue;
    }

    if (!killPointer)
      continue;

    // Deal with undead pointers
    MadeChange |= RemoveUndeadPointers(killPointer, BBI,
                                       deadPointers, possiblyDead);
  }

  return MadeChange;
}

/// RemoveUndeadPointers - takes an instruction and a setvector of
/// dead instructions.  If I is dead, it is erased, and its operands are
/// checked for deadness.  If they are dead, they are added to the dead
/// setvector.
bool DSE::RemoveUndeadPointers(Value* killPointer,
                                BasicBlock::iterator& BBI,
                                SmallPtrSet<AllocaInst*, 64>& deadPointers,
                                SetVector<Instruction*>& possiblyDead) {
  TargetData &TD = getAnalysis<TargetData>();
  AliasAnalysis &AA = getAnalysis<AliasAnalysis>();
  MemoryDependenceAnalysis& MD = getAnalysis<MemoryDependenceAnalysis>();

  bool MadeChange = false;

  std::vector<Instruction*> undead;

  for (SmallPtrSet<AllocaInst*, 64>::iterator I = deadPointers.begin(),
      E = deadPointers.end(); I != E; ++I) {
    // Get size information for the alloca
    unsigned pointerSize = ~0UL;
    if (ConstantInt* C = dyn_cast<ConstantInt>((*I)->getArraySize()))
      pointerSize = C->getZExtValue() * \
                    TD.getTypeSize((*I)->getAllocatedType());

    // See if this pointer could alias it
    AliasAnalysis::AliasResult A = AA.alias(*I, pointerSize,
                                            killPointer, ~0UL);

    // If it must-alias and a store, we can delete it
    if (isa<StoreInst>(BBI) && A == AliasAnalysis::MustAlias) {
      StoreInst* S = cast<StoreInst>(BBI);

      // Remove it!
      MD.removeInstruction(S);

      // DCE instructions only used to calculate that store
      if (Instruction* D = dyn_cast<Instruction>(S->getOperand(0)))
        possiblyDead.insert(D);
      if (Instruction* D = dyn_cast<Instruction>(S->getOperand(1)))
        possiblyDead.insert(D);

      BBI++;
      S->eraseFromParent();
      NumFastStores++;
      MadeChange = true;

      continue;

      // Otherwise, it is undead
      } else if (A != AliasAnalysis::NoAlias)
        undead.push_back(*I);
  }

  for (std::vector<Instruction*>::iterator I = undead.begin(), E = undead.end();
       I != E; ++I)
    deadPointers.erase(*I);

  return MadeChange;
}

/// DeleteDeadInstructionChains - takes an instruction and a setvector of
/// dead instructions.  If I is dead, it is erased, and its operands are
/// checked for deadness.  If they are dead, they are added to the dead
/// setvector.
void DSE::DeleteDeadInstructionChains(Instruction *I,
                                      SetVector<Instruction*> &DeadInsts) {
  // Instruction must be dead.
  if (!I->use_empty() || !isInstructionTriviallyDead(I)) return;

  // Let the memory dependence know
  getAnalysis<MemoryDependenceAnalysis>().removeInstruction(I);

  // See if this made any operands dead.  We do it this way in case the
  // instruction uses the same operand twice.  We don't want to delete a
  // value then reference it.
  for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) {
    if (I->getOperand(i)->hasOneUse())
      if (Instruction* Op = dyn_cast<Instruction>(I->getOperand(i)))
        DeadInsts.insert(Op);      // Attempt to nuke it later.

    I->setOperand(i, 0);         // Drop from the operand list.
  }

  I->eraseFromParent();
  ++NumFastOther;
}
<|endoftext|>


<commit_before>/*
 * benchmarks/benchmark-dense-solve.C
 *
 * Copyright (C) 2019 The LinBox group
 * Author: J-G Dumas
 * ========LICENCE========
 * This file is part of the library LinBox.
 *
 * LinBox is free software: you can redistribute it and/or modify
 * it under the terms of the  GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 */

/**\file benchmarks/benchmark-dense-solve.C
   \brief Solving dense linear system over Q or Zp.
   \ingroup benchmarks
*/

#include "linbox/linbox-config.h"
#include <iostream>

#include <givaro/modular.h>
#include "linbox/util/args-parser.h"
#include "linbox/matrix/sparse-matrix.h"
#include "linbox/solutions/solve.h"
#include "linbox/util/matrix-stream.h"
#include "linbox/solutions/methods.h"

#ifdef _DEBUG
#define _BENCHMARKS_DEBUG_
#endif

using namespace LinBox;
typedef Givaro::ZRing<Givaro::Integer> Ints;

int main (int argc, char **argv)
{
    Givaro::Integer q = -1 ;
    size_t nbiter = 3 ;
    size_t n = 500 ;
    size_t bits = 10;
//     size_t p = 0;

    Argument as[] = {
        { 'i', "-i R", "Set number of repetitions.",       TYPE_INT , &nbiter },
        { 'q', "-q Q", "Set the field characteristic (-1 for rationals).", TYPE_INTEGER , &q },
        { 'n', "-n N", "Set the matrix dimension.",      TYPE_INT , &n },
        { 'b', "-b B", "bit size", TYPE_INT , &bits },
//         { 'p', "-p P", "0 for sequential, 1 for 2D iterative, 2 for 2D rec, 3 for 2D rec adaptive, 4 for 3D rec in-place, 5 for 3D rec, 6 for 3D rec adaptive.", TYPE_INT , &p },
        END_OF_ARGUMENTS
    };

    LinBox::parseArguments(argc,argv,as);

    bool ModComp = false;
    if (q > 0) ModComp = true;

    Timer chrono;
    std::vector<std::pair<double,double>> timebits(nbiter);
    for(size_t iter=0; iter<nbiter; ++iter) {

        if (ModComp) {

            typedef Givaro::Modular<double> Field;
            Field F(q);
            Field::RandIter G(F);

#ifdef _BENCHMARKS_DEBUG_
            std::clog << "Setting A ... " << std::endl;
#endif
            chrono.start();
            DenseMatrix<Field> A(F,n,n);
            PAR_BLOCK { FFLAS::pfrand(F,G, n,n,A.getPointer(),n); }
            chrono.stop();
#ifdef _BENCHMARKS_DEBUG_
            std::clog << "... A is " << A.rowdim() << " by " << A.coldim() << ", " << chrono << std::endl;
            if (A.rowdim() <= 20 && A.coldim() <= 20) A.write(std::clog <<"A:=",Tag::FileFormat::Maple) << ';' << std::endl;
#endif
            DenseVector<Field> X(F, A.coldim()),B(F, A.rowdim());
            PAR_BLOCK { FFLAS::pfrand(F,G, n,1,B.getPointer(),1); }
#ifdef _BENCHMARKS_DEBUG_
            std::clog << "B is [";
            for(const auto& it: B)
                F.write(std::clog, it) << ' ';
            std::clog << ']' << std::endl;
#endif

                // DenseElimination
            chrono.start();
            solve (X, A, B, Method::DenseElimination());
            chrono.stop();

#ifdef _BENCHMARKS_DEBUG_
            std::clog << "(DenseElimination) Solution is [";
            for(const auto& it: X)
                F.write(std::clog, it) << ' ';
            std::clog << ']' << std::endl;
#endif
            timebits[iter].second=Givaro::logtwo(GIVMAX(X.front(), 1));
        } else {

            typedef Ints Integers;
            Integers ZZ;
            Integers::RandIter G(ZZ,bits);
#ifdef _BENCHMARKS_DEBUG_
            std::clog << "Reading A ... " << std::endl;
            chrono.start();
#endif
            DenseMatrix<Integers> A(ZZ, n, n);
            PAR_BLOCK { FFLAS::pfrand(ZZ,G, n,n,A.getPointer(),n); }
#ifdef _BENCHMARKS_DEBUG_
            chrono.stop();
            std::clog << "... A is " << A.rowdim() << " by " << A.coldim() << ", " << chrono << std::endl;
            if (A.rowdim() <= 20 && A.coldim() <= 20) A.write(std::clog <<"A:=",Tag::FileFormat::Maple) << ';' << std::endl;
#endif
            Givaro::IntegerDom::Element d;

            DenseVector<Integers> X(ZZ, A.coldim()),B(ZZ, A.rowdim());
            PAR_BLOCK { FFLAS::pfrand(ZZ,G, n,1,B.getPointer(),1); }

#ifdef _BENCHMARKS_DEBUG_
            std::clog << "B is [";
            for(const auto& it: B)
                ZZ.write(std::clog, it) << ' ';
            std::clog << ']' << std::endl;
#endif

                // DenseElimination
            chrono.start();
            solve (X, d, A, B, RingCategories::IntegerTag(), Method::DenseElimination());
            chrono.stop();

#ifdef _BENCHMARKS_DEBUG_
            std::clog << "(DenseElimination) Solution is [";
            for(const auto& it: X) ZZ.write(std::clog, it) << ' ';
            ZZ.write(std::clog << "] / ", d)<< std::endl;
#endif

            timebits[iter].second=Givaro::logtwo(d);
        }

        timebits[iter].first=chrono.usertime();
    }

#ifdef _BENCHMARKS_DEBUG_
    for(const auto& it: timebits)
        std::clog << it.first << "s, " << it.second << " bits" << std::endl;
#endif

    std::sort(timebits.begin(), timebits.end(),
              [](const std::pair<double,double> & a,
                 const std::pair<double,double> & b) -> bool {
        return a.first > b.first; });

    std::cout << "Time: " << timebits[nbiter/2].first
              << " Bitsize: " << timebits[nbiter/2].second;

    FFLAS::writeCommandString(std::cout, as) << std::endl;

    return 0;
}
<commit_msg>logtwo q<commit_after>/*
 * benchmarks/benchmark-dense-solve.C
 *
 * Copyright (C) 2019 The LinBox group
 * Author: J-G Dumas
 * ========LICENCE========
 * This file is part of the library LinBox.
 *
 * LinBox is free software: you can redistribute it and/or modify
 * it under the terms of the  GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 * ========LICENCE========
 */

/**\file benchmarks/benchmark-dense-solve.C
   \brief Solving dense linear system over Q or Zp.
   \ingroup benchmarks
*/

#include "linbox/linbox-config.h"
#include <iostream>

#include <givaro/modular.h>
#include "linbox/util/args-parser.h"
#include "linbox/matrix/sparse-matrix.h"
#include "linbox/solutions/solve.h"
#include "linbox/util/matrix-stream.h"
#include "linbox/solutions/methods.h"

#ifdef _DEBUG
#define _BENCHMARKS_DEBUG_
#endif

using namespace LinBox;
typedef Givaro::ZRing<Givaro::Integer> Ints;

int main (int argc, char **argv)
{
    Givaro::Integer q = -1 ;
    size_t nbiter = 3 ;
    size_t n = 500 ;
    size_t bits = 10;
//     size_t p = 0;

    Argument as[] = {
        { 'i', "-i R", "Set number of repetitions.",       TYPE_INT , &nbiter },
        { 'q', "-q Q", "Set the field characteristic (-1 for rationals).", TYPE_INTEGER , &q },
        { 'n', "-n N", "Set the matrix dimension.",      TYPE_INT , &n },
        { 'b', "-b B", "bit size", TYPE_INT , &bits },
//         { 'p', "-p P", "0 for sequential, 1 for 2D iterative, 2 for 2D rec, 3 for 2D rec adaptive, 4 for 3D rec in-place, 5 for 3D rec, 6 for 3D rec adaptive.", TYPE_INT , &p },
        END_OF_ARGUMENTS
    };

    LinBox::parseArguments(argc,argv,as);

    bool ModComp = false;
    if (q > 0) ModComp = true;

    Timer chrono;
    std::vector<std::pair<double,double>> timebits(nbiter);
    for(size_t iter=0; iter<nbiter; ++iter) {

        if (ModComp) {

            typedef Givaro::Modular<double> Field;
            Field F(q);
            Field::RandIter G(F);

#ifdef _BENCHMARKS_DEBUG_
            std::clog << "Setting A ... " << std::endl;
#endif
            chrono.start();
            DenseMatrix<Field> A(F,n,n);
            PAR_BLOCK { FFLAS::pfrand(F,G, n,n,A.getPointer(),n); }
            chrono.stop();
#ifdef _BENCHMARKS_DEBUG_
            std::clog << "... A is " << A.rowdim() << " by " << A.coldim() << ", " << chrono << std::endl;
            if (A.rowdim() <= 20 && A.coldim() <= 20) A.write(std::clog <<"A:=",Tag::FileFormat::Maple) << ';' << std::endl;
#endif
            DenseVector<Field> X(F, A.coldim()),B(F, A.rowdim());
            PAR_BLOCK { FFLAS::pfrand(F,G, n,1,B.getPointer(),1); }
#ifdef _BENCHMARKS_DEBUG_
            std::clog << "B is [";
            for(const auto& it: B)
                F.write(std::clog, it) << ' ';
            std::clog << ']' << std::endl;
#endif

                // DenseElimination
            chrono.start();
            solve (X, A, B, Method::DenseElimination());
            chrono.stop();

#ifdef _BENCHMARKS_DEBUG_
            std::clog << "(DenseElimination) Solution is [";
            for(const auto& it: X)
                F.write(std::clog, it) << ' ';
            std::clog << ']' << std::endl;
#endif
            timebits[iter].second=Givaro::logtwo(q);
        } else {

            typedef Ints Integers;
            Integers ZZ;
            Integers::RandIter G(ZZ,bits);
#ifdef _BENCHMARKS_DEBUG_
            std::clog << "Reading A ... " << std::endl;
            chrono.start();
#endif
            DenseMatrix<Integers> A(ZZ, n, n);
            PAR_BLOCK { FFLAS::pfrand(ZZ,G, n,n,A.getPointer(),n); }
#ifdef _BENCHMARKS_DEBUG_
            chrono.stop();
            std::clog << "... A is " << A.rowdim() << " by " << A.coldim() << ", " << chrono << std::endl;
            if (A.rowdim() <= 20 && A.coldim() <= 20) A.write(std::clog <<"A:=",Tag::FileFormat::Maple) << ';' << std::endl;
#endif
            Givaro::IntegerDom::Element d;

            DenseVector<Integers> X(ZZ, A.coldim()),B(ZZ, A.rowdim());
            PAR_BLOCK { FFLAS::pfrand(ZZ,G, n,1,B.getPointer(),1); }

#ifdef _BENCHMARKS_DEBUG_
            std::clog << "B is [";
            for(const auto& it: B)
                ZZ.write(std::clog, it) << ' ';
            std::clog << ']' << std::endl;
#endif

                // DenseElimination
            chrono.start();
            solve (X, d, A, B, RingCategories::IntegerTag(), Method::DenseElimination());
            chrono.stop();

#ifdef _BENCHMARKS_DEBUG_
            std::clog << "(DenseElimination) Solution is [";
            for(const auto& it: X) ZZ.write(std::clog, it) << ' ';
            ZZ.write(std::clog << "] / ", d)<< std::endl;
#endif

            timebits[iter].second=Givaro::logtwo(d);
        }

        timebits[iter].first=chrono.usertime();
    }

#ifdef _BENCHMARKS_DEBUG_
    for(const auto& it: timebits)
        std::clog << it.first << "s, " << it.second << " bits" << std::endl;
#endif

    std::sort(timebits.begin(), timebits.end(),
              [](const std::pair<double,double> & a,
                 const std::pair<double,double> & b) -> bool {
        return a.first > b.first; });

    std::cout << "Time: " << timebits[nbiter/2].first
              << " Bitsize: " << timebits[nbiter/2].second;

    FFLAS::writeCommandString(std::cout, as) << std::endl;

    return 0;
}
<|endoftext|>