<commit_before>#include <dune/common/mpihelper.hh>

#include <map>
#include <string>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>

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

namespace Dune {
namespace Stuff {
namespace Common {

void Profiler::startTiming(const std::string section_name, const int i)
{
    const std::string section = section_name + toString(i);
    startTiming(section);
}

long  Profiler::stopTiming(const std::string section_name, const int i)
{
    const std::string section = section_name + toString(i);
    return stopTiming(section);
}

long  Profiler::getTiming(const std::string section_name, const int i) const
{
    const std::string section = section_name + toString(i);
    return getTiming(section);
}

void Profiler::resetTiming(const std::string section_name, const int i)
{
    const std::string section = section_name + toString(i);
    return resetTiming(section);
}

void Profiler::resetTiming(const std::string section_name)
{
    try {
        stopTiming(section_name);
    }
    catch (Dune::RangeError) {
        //ok, timer simply wasn't running
    }
    Datamap& current_data = datamaps_[current_run_number_];
    current_data[section_name] = 0;
}

void Profiler::startTiming(const std::string section_name) {
  if ( current_run_number_ >= datamaps_.size() )
  {
    datamaps_.push_back( Datamap() );
  }

  const KnownTimersMap::iterator section = known_timers_map_.find(section_name);
  if ( section != known_timers_map_.end() )
  {
    if (section->second.first)     // timer currently running
      return;

    section->second.first = true;  // set active, start with new
    section->second.second = TimingData(section_name);
  } else {
    // init new section
    known_timers_map_[section_name] = std::make_pair( true, TimingData(section_name) );
  }
} // StartTiming

long Profiler::stopTiming(const std::string section_name) {
  assert( current_run_number_ < datamaps_.size() );
  if ( known_timers_map_.find(section_name) == known_timers_map_.end() )
    DUNE_THROW(Dune::RangeError, "trying to stop timer " << section_name << " that wasn't started\n");

  known_timers_map_[section_name].first = false;//marks as not running
  TimingData& timing = known_timers_map_[section_name].second;
  timing.stop();
  long delta = timing.delta();
  Datamap& current_data = datamaps_[current_run_number_];
  if ( current_data.find(section_name) == current_data.end() )
    current_data[section_name] = delta;
  else
    current_data[section_name] += delta;
  return delta;
} // StopTiming

long Profiler::getTiming(const std::string section_name) const {
  assert( current_run_number_ < datamaps_.size() );
  return getTimingIdx(section_name, current_run_number_);
}

long Profiler::getTimingIdx(const std::string section_name, const int run_number) const {
  assert( run_number < int( datamaps_.size() ) );
  const Datamap& data = datamaps_[run_number];
  Datamap::const_iterator section = data.find(section_name);
  if ( section == data.end() )
  {
    //timer might still be running
    const auto& timer_it = known_timers_map_.find(section_name);
    if (timer_it != known_timers_map_.end())
        return timer_it->second.second.delta();
    ASSERT_EXCEPTION(false, "no timer found: " + section_name);
    return -1;
  }
  return section->second;
} // GetTiming

void Profiler::reset(const int numRuns) {
  if(!(numRuns > 0))
      DUNE_THROW(Dune::RangeError, "preparing the profiler for 0 runs is moronic");
  datamaps_.clear();
  datamaps_ = DatamapVector( numRuns, Datamap() );
  current_run_number_ = 0;
} // Reset

void Profiler::addCount(const int num) {
  counters_[num] += 1;
}

void Profiler::nextRun() {
    //set all known timers to "stopped"
    for (auto& timer_it : known_timers_map_)
        timer_it.second.first = false;
  current_run_number_++;
}

void Profiler::outputAveraged(const int refineLevel,
                              const long numDofs,
                              const double scale_factor) const {
  const auto& comm = Dune::MPIHelper::getCollectiveCommunication();
  const int numProce = comm.size();

  boost::format csv_name("p%d_refinelvl_%d.csv");
  csv_name % numProce % refineLevel;
  boost::filesystem::path filename(output_dir_);
  filename /= csv_name.str();

  if (comm.rank() == 0)
    std::cout << "Profiling info in: " << filename << std::endl;

  #ifndef NDEBUG
  for (const auto& count : counters_)
  {
    std::cout << "proc " << comm.rank() << " bId " << count.first << " count " << count.second << std::endl;
  }
  #endif // ifndef NDEBUG

  boost::filesystem::ofstream csv(filename);

  std::map< std::string, long > averages_map;
  for (const auto& datamap : datamaps_)
  {
    for (const auto& timing : datamap)
    {
      //! this used to be GetTiming( it->second ), which is only valid thru an implicit and wrong conversion..
      averages_map[timing.first] += getTiming(timing.first);
    }
  }

// outputs column names
  csv << "refine" << csv_sep  << "processes" << csv_sep << "numDofs" << csv_sep << "L1 error" << csv_sep;
  for (const auto& avg_item : averages_map)
  {
    csv << avg_item.first << csv_sep;
  }
  csv << "Speedup (total)" << csv_sep << "Speedup (ohne Solver)" << std::endl;

// outputs column values
  csv << refineLevel << csv_sep << comm.size() << csv_sep << numDofs << csv_sep << 0 << csv_sep;
  for (const auto& avg_item : averages_map)
  {
    long clock_count = avg_item.second;
    clock_count = long( comm.sum(clock_count) / double(scale_factor * numProce) );
    csv << clock_count / double(datamaps_.size()) << csv_sep;
  }
  csv << "=I$2/I2" << csv_sep << "=SUM(E$2:G$2)/SUM(E2:G2)" << std::endl;
  csv.close();
} // OutputAveraged

void Profiler::output(const Profiler::InfoContainer& run_infos, const double scale_factor) const{
  const auto& comm = Dune::MPIHelper::getCollectiveCommunication();
  const int numProce = comm.size();

  boost::filesystem::path filename(output_dir_);
  filename /= (boost::format("prof_p%d.csv") % numProce).str();
  outputCommon(run_infos, filename, scale_factor);
} // Output

void Profiler::outputMap(const Profiler::InfoContainerMap& run_infos_map, const double scale_factor) const {
  const auto& comm = Dune::MPIHelper::getCollectiveCommunication();
  for(const auto& el : run_infos_map)
  {
    boost::filesystem::path filename(output_dir_);
    filename /= (boost::format(
                     "prof_p%d_ref%s.csv") % comm.size() % el.first).str();
    outputCommon(el.second, filename, scale_factor);
  }
} // OutputMap

void Profiler::outputCommon(const Profiler::InfoContainer& run_infos,
                            const boost::filesystem::path& filename,
                            const double scale_factor) const {
  const auto& comm = Dune::MPIHelper::getCollectiveCommunication();
  const int numProce = comm.size();

  if (comm.rank() == 0)
    std::cout << "Profiling info in: " << filename << std::endl;

  #ifndef NDEBUG
  for (const auto& count : counters_)
  {
    std::cout << "proc " << comm.rank() << " bId " << count.first << " count " << count.second << std::endl;
  }
  #endif // ifndef NDEBUG

  boost::filesystem::ofstream csv(filename);
// outputs column names
  if (run_infos.size())
  {
      csv << "refine" << csv_sep  << "processes" << csv_sep  << "numDofs" << csv_sep << "L2_error" << csv_sep ;
      for (Datamap::const_iterator it = datamaps_[0].begin(); it != datamaps_[0].end(); ++it)
      {
        csv << it->first << csv_sep;
      }
  }
  csv << "Relative_total_time" << csv_sep << "compiler" << std::endl;

// outputs column values
  std::size_t idx = 0;
  for (const Datamap& data_map : datamaps_)
  {
    if(idx < run_infos.size()) {
        const Dune::Stuff::Common::RunInfo& info = run_infos[idx];
        csv << boost::format("%d%s%d%s%d%s%e,") % info.refine_level % csv_sep
                                             % comm.size() % csv_sep
                                             % info.codim0 % csv_sep
                                             % ( info.L2Errors.size() ? info.L2Errors[0] : double(-1) );
    }

    for (Datamap::const_iterator it = data_map.begin(); it != data_map.end(); ++it)
    {
      long clock_count = getTimingIdx(it->first, idx);
      clock_count = long( comm.sum(clock_count) / double(scale_factor * numProce) );
      csv << clock_count << csv_sep;
    }
    csv << boost::format("=1/I$2*I%d%s%s\n") % (idx + 2) % csv_sep % BOOST_COMPILER;

    idx++;
  }
  csv.close();
} // OutputCommon

void Profiler::setOutputdir(const std::string dir)
{
  output_dir_ = dir;
  Dune::Stuff::Common::testCreateDirectory( output_dir_ );
}

void Profiler::outputTimings(const std::string csv) const
{
    const auto& comm = Dune::MPIHelper::getCollectiveCommunication();
    boost::filesystem::path dir(output_dir_);
    boost::filesystem::path filename = dir / (boost::format("%s_p%08d.csv") % csv % comm.rank()).str();
    boost::filesystem::ofstream out(filename);
    outputTimings(out);
    if (comm.rank() == 0) {
        boost::filesystem::path a_filename = dir / (boost::format("%s.csv") % csv).str();
        boost::filesystem::ofstream a_out(a_filename);
        outputTimingsAll(a_out);
    }
}

void Profiler::outputTimingsAll(std::ostream& out) const
{
  if (datamaps_.size() < 1)
    return;
  //csv header:
  const auto& comm = Dune::MPIHelper::getCollectiveCommunication();
  out << "run";
  for (const auto& section : datamaps_[0]) {
    out << csv_sep << section.first << "_avg" << csv_sep << section.first << "_sum";
  }
  int i = 0;
  for (const auto& datamap : datamaps_) {
    out << std::endl << i;
    for (const auto& section : datamap) {
      auto sum = comm.sum(section.second);
      out << csv_sep << sum / float(comm.size()) << csv_sep << sum;
    }
    out << std::endl;
  }
}

void Profiler::outputTimings(std::ostream& out) const
{
  if (datamaps_.size() < 1)
    return;
  //csv header:
  out << "run";
  for (const auto& section : datamaps_[0]) {
    out << csv_sep << section.first;
  }
  int i = 0;
  for (const auto& datamap : datamaps_) {
    out << std::endl << i;
    for (const auto& section : datamap) {
      out << csv_sep << section.second;
    }
    out << std::endl;
  }
}

Profiler::Profiler()
  : csv_sep(",")
{
  reset(1);
  setOutputdir("./profiling");
}

Profiler::~Profiler()
{}

} // namespace Common
} // namespace Stuff
} // namespace Dune
<commit_msg>[profiler] fix mpi compile<commit_after>#include <dune/common/mpihelper.hh>

#include <map>
#include <string>
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>

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

namespace Dune {
namespace Stuff {
namespace Common {

void Profiler::startTiming(const std::string section_name, const int i)
{
    const std::string section = section_name + toString(i);
    startTiming(section);
}

long  Profiler::stopTiming(const std::string section_name, const int i)
{
    const std::string section = section_name + toString(i);
    return stopTiming(section);
}

long  Profiler::getTiming(const std::string section_name, const int i) const
{
    const std::string section = section_name + toString(i);
    return getTiming(section);
}

void Profiler::resetTiming(const std::string section_name, const int i)
{
    const std::string section = section_name + toString(i);
    return resetTiming(section);
}

void Profiler::resetTiming(const std::string section_name)
{
    try {
        stopTiming(section_name);
    }
    catch (Dune::RangeError) {
        //ok, timer simply wasn't running
    }
    Datamap& current_data = datamaps_[current_run_number_];
    current_data[section_name] = 0;
}

void Profiler::startTiming(const std::string section_name) {
  if ( current_run_number_ >= datamaps_.size() )
  {
    datamaps_.push_back( Datamap() );
  }

  const KnownTimersMap::iterator section = known_timers_map_.find(section_name);
  if ( section != known_timers_map_.end() )
  {
    if (section->second.first)     // timer currently running
      return;

    section->second.first = true;  // set active, start with new
    section->second.second = TimingData(section_name);
  } else {
    // init new section
    known_timers_map_[section_name] = std::make_pair( true, TimingData(section_name) );
  }
} // StartTiming

long Profiler::stopTiming(const std::string section_name) {
  assert( current_run_number_ < datamaps_.size() );
  if ( known_timers_map_.find(section_name) == known_timers_map_.end() )
    DUNE_THROW(Dune::RangeError, "trying to stop timer " << section_name << " that wasn't started\n");

  known_timers_map_[section_name].first = false;//marks as not running
  TimingData& timing = known_timers_map_[section_name].second;
  timing.stop();
  long delta = timing.delta();
  Datamap& current_data = datamaps_[current_run_number_];
  if ( current_data.find(section_name) == current_data.end() )
    current_data[section_name] = delta;
  else
    current_data[section_name] += delta;
  return delta;
} // StopTiming

long Profiler::getTiming(const std::string section_name) const {
  assert( current_run_number_ < datamaps_.size() );
  return getTimingIdx(section_name, current_run_number_);
}

long Profiler::getTimingIdx(const std::string section_name, const int run_number) const {
  assert( run_number < int( datamaps_.size() ) );
  const Datamap& data = datamaps_[run_number];
  Datamap::const_iterator section = data.find(section_name);
  if ( section == data.end() )
  {
    //timer might still be running
    const auto& timer_it = known_timers_map_.find(section_name);
    if (timer_it != known_timers_map_.end())
        return timer_it->second.second.delta();
    ASSERT_EXCEPTION(false, "no timer found: " + section_name);
    return -1;
  }
  return section->second;
} // GetTiming

void Profiler::reset(const int numRuns) {
  if(!(numRuns > 0))
      DUNE_THROW(Dune::RangeError, "preparing the profiler for 0 runs is moronic");
  datamaps_.clear();
  datamaps_ = DatamapVector( numRuns, Datamap() );
  current_run_number_ = 0;
} // Reset

void Profiler::addCount(const int num) {
  counters_[num] += 1;
}

void Profiler::nextRun() {
    //set all known timers to "stopped"
    for (auto& timer_it : known_timers_map_)
        timer_it.second.first = false;
  current_run_number_++;
}

void Profiler::outputAveraged(const int refineLevel,
                              const long numDofs,
                              const double scale_factor) const {
  const auto& comm = Dune::MPIHelper::getCollectiveCommunication();
  const int numProce = comm.size();

  boost::format csv_name("p%d_refinelvl_%d.csv");
  csv_name % numProce % refineLevel;
  boost::filesystem::path filename(output_dir_);
  filename /= csv_name.str();

  if (comm.rank() == 0)
    std::cout << "Profiling info in: " << filename << std::endl;

  #ifndef NDEBUG
  for (const auto& count : counters_)
  {
    std::cout << "proc " << comm.rank() << " bId " << count.first << " count " << count.second << std::endl;
  }
  #endif // ifndef NDEBUG

  boost::filesystem::ofstream csv(filename);

  std::map< std::string, long > averages_map;
  for (const auto& datamap : datamaps_)
  {
    for (const auto& timing : datamap)
    {
      //! this used to be GetTiming( it->second ), which is only valid thru an implicit and wrong conversion..
      averages_map[timing.first] += getTiming(timing.first);
    }
  }

// outputs column names
  csv << "refine" << csv_sep  << "processes" << csv_sep << "numDofs" << csv_sep << "L1 error" << csv_sep;
  for (const auto& avg_item : averages_map)
  {
    csv << avg_item.first << csv_sep;
  }
  csv << "Speedup (total)" << csv_sep << "Speedup (ohne Solver)" << std::endl;

// outputs column values
  csv << refineLevel << csv_sep << comm.size() << csv_sep << numDofs << csv_sep << 0 << csv_sep;
  for (const auto& avg_item : averages_map)
  {
    long clock_count = avg_item.second;
    clock_count = long( comm.sum(clock_count) / double(scale_factor * numProce) );
    csv << clock_count / double(datamaps_.size()) << csv_sep;
  }
  csv << "=I$2/I2" << csv_sep << "=SUM(E$2:G$2)/SUM(E2:G2)" << std::endl;
  csv.close();
} // OutputAveraged

void Profiler::output(const Profiler::InfoContainer& run_infos, const double scale_factor) const{
  const auto& comm = Dune::MPIHelper::getCollectiveCommunication();
  const int numProce = comm.size();

  boost::filesystem::path filename(output_dir_);
  filename /= (boost::format("prof_p%d.csv") % numProce).str();
  outputCommon(run_infos, filename, scale_factor);
} // Output

void Profiler::outputMap(const Profiler::InfoContainerMap& run_infos_map, const double scale_factor) const {
  const auto& comm = Dune::MPIHelper::getCollectiveCommunication();
  for(const auto& el : run_infos_map)
  {
    boost::filesystem::path filename(output_dir_);
    filename /= (boost::format(
                     "prof_p%d_ref%s.csv") % comm.size() % el.first).str();
    outputCommon(el.second, filename, scale_factor);
  }
} // OutputMap

void Profiler::outputCommon(const Profiler::InfoContainer& run_infos,
                            const boost::filesystem::path& filename,
                            const double scale_factor) const {
  const auto& comm = Dune::MPIHelper::getCollectiveCommunication();
  const int numProce = comm.size();

  if (comm.rank() == 0)
    std::cout << "Profiling info in: " << filename << std::endl;

  #ifndef NDEBUG
  for (const auto& count : counters_)
  {
    std::cout << "proc " << comm.rank() << " bId " << count.first << " count " << count.second << std::endl;
  }
  #endif // ifndef NDEBUG

  boost::filesystem::ofstream csv(filename);
// outputs column names
  if (run_infos.size())
  {
      csv << "refine" << csv_sep  << "processes" << csv_sep  << "numDofs" << csv_sep << "L2_error" << csv_sep ;
      for (Datamap::const_iterator it = datamaps_[0].begin(); it != datamaps_[0].end(); ++it)
      {
        csv << it->first << csv_sep;
      }
  }
  csv << "Relative_total_time" << csv_sep << "compiler" << std::endl;

// outputs column values
  std::size_t idx = 0;
  for (const Datamap& data_map : datamaps_)
  {
    if(idx < run_infos.size()) {
        const Dune::Stuff::Common::RunInfo& info = run_infos[idx];
        csv << boost::format("%d%s%d%s%d%s%e,") % info.refine_level % csv_sep
                                             % comm.size() % csv_sep
                                             % info.codim0 % csv_sep
                                             % ( info.L2Errors.size() ? info.L2Errors[0] : double(-1) );
    }

    for (Datamap::const_iterator it = data_map.begin(); it != data_map.end(); ++it)
    {
      long clock_count = getTimingIdx(it->first, idx);
      clock_count = long( comm.sum(clock_count) / double(scale_factor * numProce) );
      csv << clock_count << csv_sep;
    }
    csv << boost::format("=1/I$2*I%d%s%s\n") % (idx + 2) % csv_sep % BOOST_COMPILER;

    idx++;
  }
  csv.close();
} // OutputCommon

void Profiler::setOutputdir(const std::string dir)
{
  output_dir_ = dir;
  Dune::Stuff::Common::testCreateDirectory( output_dir_ );
}

void Profiler::outputTimings(const std::string csv) const
{
    const auto& comm = Dune::MPIHelper::getCollectiveCommunication();
    boost::filesystem::path dir(output_dir_);
    boost::filesystem::path filename = dir / (boost::format("%s_p%08d.csv") % csv % comm.rank()).str();
    boost::filesystem::ofstream out(filename);
    outputTimings(out);
    if (comm.rank() == 0) {
        boost::filesystem::path a_filename = dir / (boost::format("%s.csv") % csv).str();
        boost::filesystem::ofstream a_out(a_filename);
        outputTimingsAll(a_out);
    }
}

void Profiler::outputTimingsAll(std::ostream& out) const
{
  if (datamaps_.size() < 1)
    return;
  //csv header:
  const auto& comm = Dune::MPIHelper::getCollectiveCommunication();
  out << "run";
  for (const auto& section : datamaps_[0]) {
    out << csv_sep << section.first << "_avg" << csv_sep << section.first << "_sum";
  }
  int i = 0;
  for (const auto& datamap : datamaps_) {
    out << std::endl << i;
    for (const auto& section : datamap) {
      auto val = section.second;
      auto sum = comm.sum(val);
      out << csv_sep << sum / float(comm.size()) << csv_sep << sum;
    }
    out << std::endl;
  }
}

void Profiler::outputTimings(std::ostream& out) const
{
  if (datamaps_.size() < 1)
    return;
  //csv header:
  out << "run";
  for (const auto& section : datamaps_[0]) {
    out << csv_sep << section.first;
  }
  int i = 0;
  for (const auto& datamap : datamaps_) {
    out << std::endl << i;
    for (const auto& section : datamap) {
      out << csv_sep << section.second;
    }
    out << std::endl;
  }
}

Profiler::Profiler()
  : csv_sep(",")
{
  reset(1);
  setOutputdir("./profiling");
}

Profiler::~Profiler()
{}

} // namespace Common
} // namespace Stuff
} // namespace Dune
<|endoftext|>


<commit_before>#ifndef __CONCURRENCY_FIFO_CHECKER_HPP__
#define __CONCURRENCY_FIFO_CHECKER_HPP__

#include <vector>

#include <boost/function.hpp>

#include "arch/arch.hpp"
#include "utils2.hpp"

// The memcached order_source_t and the backfill_receiver_t will want
// to be in distinct buckets.

// We'll need our order sources' buckets (operating for the same code
// path) at any given point in time to be distinct values. The
// backfill receiver (be it on the master side or slave side) gets
// bucket 0.  Then the memcache connections get buckets 1,2,3,...
//
// Btree slice operations then get an order source with bucket 0,
// since they operate independently and their tokens reach a different
// set of order sinks.
const int BACKFILL_RECEIVER_ORDER_SOURCE_BUCKET = 0;
const int MEMCACHE_START_BUCKET = 1;

/* Order tokens of the same bucket need to arrive at order sinks in a
   certain order.  Pretending that read_mode is always false, they
   need to arrive by ascending order of their value -- the same order
   that they were created in.  This is because write operations cannot
   be reordered.  However, read operations may be shuffled around, and
   so may order_tokens with read_mode set to true.
 */
class order_token_t {
public:
    static const order_token_t ignore;

#ifndef NDEBUG
    // By default we construct a totally invalid order token, not
    // equal to ignore, that must be initialized.
    order_token_t();

    order_token_t with_read_mode() const;

    int bucket() const;
    bool read_mode() const;
    int64_t value() const;
    const std::string& tag() const;
#else
    order_token_t() { }
    order_token_t with_read_mode() const { return order_token_t(); }

    int bucket() const { return 0; }
    bool read_mode() const { return true; }
    int64_t value() const { return 0; }
    std::string tag() const { return ""; }
#endif  // ifndef NDEBUG

private:

#ifndef NDEBUG
    order_token_t(int bucket, int64_t x, bool read_mode, const std::string& tag);
    int bucket_;
    bool read_mode_;
    int64_t value_;
    // This tag would be inefficient on VC++ or some other non-GNU
    // std::string implementation, since we copy by value.
    std::string tag_;
#endif  // ifndef NDEBUG

    friend class order_source_t;
    friend class order_sink_t;
    friend class backfill_receiver_order_source_t;
    friend class plain_sink_t;
    friend class contiguous_order_sink_t;
};

/* Buckets are like file descriptors.  We don't want two order sources
   to have the same bucket, and we can reuse buckets when an order
   source is destroyed.  A pigeoncoop keeps track of all the available
   pigeonholes and what the initial value should be for the pigeon, I
   mean order source, that next gets assigned a given bucket. */
class order_source_pigeoncoop_t {
public:
#ifndef NDEBUG
    order_source_pigeoncoop_t(int starting_bucket = 0);
#else
    order_source_pigeoncoop_t(UNUSED int starting_bucket = 0) { }
#endif

    friend class order_source_t;
private:

    static void nop() { }

#ifndef NDEBUG
    void unregister_bucket(int bucket, int64_t counter);

    std::pair<int, int64_t> register_for_bucket();

    // The bucket we should use next, if free_buckets_ is empty.
    int least_unregistered_bucket_;

    // The buckets less than least_unregistered_bucket_ that are free.
    std::vector<std::pair<int, int64_t> > free_buckets_;
#endif

    DISABLE_COPYING(order_source_pigeoncoop_t);
};

/* Order sources create order tokens with increasing values for a
   specific bucket.  When they are destroyed they call a void()
   function which might inform somebody that the bucket is now
   available for reuse. */
class order_source_t {
public:
#ifndef NDEBUG
    order_source_t(int bucket = 0, boost::function<void()> unregisterator = order_source_pigeoncoop_t::nop);
    order_source_t(order_source_pigeoncoop_t *coop);
    ~order_source_t();

    order_token_t check_in(const std::string& tag);
#else
    order_source_t(UNUSED int bucket = 0, UNUSED boost::function<void()> unregisterator = order_source_pigeoncoop_t::nop) { }
    order_source_t(UNUSED order_source_pigeoncoop_t *coop) { }
    ~order_source_t() { }

    order_token_t check_in() { return order_token_t(); }
#endif  // ndef NDEBUG

private:
#ifndef NDEBUG
    int bucket_;
    int64_t counter_;
    boost::function<void ()> unregister_;
#endif  // ifndef NDEBUG

    DISABLE_COPYING(order_source_t);
};

/* A backfill receiver order source is a bit special, because when we
   backfill, we want backfill operations to get in before "realtime"
   operations.  So we play tricks with the counter depending on
   whether we're currently backfilling and whether we're checking in a
   backfill or a realtime operation.  (This assumes there will be no
   more than 4 billion backfill operations, which is ok for
   debugging purposes.)
 */
class backfill_receiver_order_source_t {
public:
#ifndef NDEBUG
    backfill_receiver_order_source_t(int bucket = BACKFILL_RECEIVER_ORDER_SOURCE_BUCKET);

    void backfill_begun();
    void backfill_done();

    order_token_t check_in_backfill_operation(const std::string& tag);
    order_token_t check_in_realtime_operation(const std::string& tag);
#else
    backfill_receiver_order_source_t(UNUSED int bucket = BACKFILL_RECEIVER_ORDER_SOURCE_BUCKET) { }

    void backfill_begun() { }
    void backfill_done() { }

    order_token_t check_in_backfill_operation() { return order_token_t(); }
    order_token_t check_in_realtime_operation() { return order_token_t(); }

#endif  // ifndef NDEBUG

private:

#ifndef NDEBUG
    int bucket_;
    int64_t counter_;
    bool backfill_active_;
#endif  // ifndef NDEBUG

    DISABLE_COPYING(backfill_receiver_order_source_t);
};

struct tagged_seen_t {
    int64_t value;
    std::string tag;

    tagged_seen_t(int64_t _value, const std::string& _tag) : value(_value), tag(_tag) { }
};

/* Eventually order tokens get to an order sink, and those of the same
   bucket had better arrive in the right order. */
class order_sink_t {
public:
#ifndef NDEBUG
    order_sink_t();

    void check_out(order_token_t token);
#else
    order_sink_t() { }

    void check_out(UNUSED  order_token_t token) { }

#endif  // ifndef NDEBUG

private:

#ifndef NDEBUG
    friend class plain_sink_t;
    static void verify_token_value_and_update(order_token_t token, std::pair<tagged_seen_t, tagged_seen_t> *ls_pair);

    // We keep two last seen values because reads can be reordered.
    // .first = last seen write, .second = max(last seen read, last seen write)
    std::vector<std::pair<tagged_seen_t, tagged_seen_t> > last_seens_;
#endif  // ifndef NDEBUG

    DISABLE_COPYING(order_sink_t);
};

// An order sink with less overhead, for situations where there is
// only one source (like the top of a btree slice) and many sinks.  If
// there's one bucket there's no point in instantiating a std::vector.
class plain_sink_t {
public:
#ifndef NDEBUG
    plain_sink_t();

    void check_out(order_token_t token);
#else
    plain_sink_t() { }

    void check_out(UNUSED  order_token_t token) { }
#endif  // ifndef NDEBUG

private:
#ifndef NDEBUG
    // The pair of last seen values.
    std::pair<tagged_seen_t, tagged_seen_t> ls_pair_;
#endif

    DISABLE_COPYING(plain_sink_t);
};

#endif  // __CONCURRENCY_FIFO_CHECKER_HPP__
<commit_msg>Fix the release build.<commit_after>#ifndef __CONCURRENCY_FIFO_CHECKER_HPP__
#define __CONCURRENCY_FIFO_CHECKER_HPP__

#include <vector>

#include <boost/function.hpp>

#include "arch/arch.hpp"
#include "utils2.hpp"

// The memcached order_source_t and the backfill_receiver_t will want
// to be in distinct buckets.

// We'll need our order sources' buckets (operating for the same code
// path) at any given point in time to be distinct values. The
// backfill receiver (be it on the master side or slave side) gets
// bucket 0.  Then the memcache connections get buckets 1,2,3,...
//
// Btree slice operations then get an order source with bucket 0,
// since they operate independently and their tokens reach a different
// set of order sinks.
const int BACKFILL_RECEIVER_ORDER_SOURCE_BUCKET = 0;
const int MEMCACHE_START_BUCKET = 1;

/* Order tokens of the same bucket need to arrive at order sinks in a
   certain order.  Pretending that read_mode is always false, they
   need to arrive by ascending order of their value -- the same order
   that they were created in.  This is because write operations cannot
   be reordered.  However, read operations may be shuffled around, and
   so may order_tokens with read_mode set to true.
 */
class order_token_t {
public:
    static const order_token_t ignore;

#ifndef NDEBUG
    // By default we construct a totally invalid order token, not
    // equal to ignore, that must be initialized.
    order_token_t();

    order_token_t with_read_mode() const;

    int bucket() const;
    bool read_mode() const;
    int64_t value() const;
    const std::string& tag() const;
#else
    order_token_t() { }
    order_token_t with_read_mode() const { return order_token_t(); }

    int bucket() const { return 0; }
    bool read_mode() const { return true; }
    int64_t value() const { return 0; }
    std::string tag() const { return ""; }
#endif  // ifndef NDEBUG

private:

#ifndef NDEBUG
    order_token_t(int bucket, int64_t x, bool read_mode, const std::string& tag);
    int bucket_;
    bool read_mode_;
    int64_t value_;
    // This tag would be inefficient on VC++ or some other non-GNU
    // std::string implementation, since we copy by value.
    std::string tag_;
#endif  // ifndef NDEBUG

    friend class order_source_t;
    friend class order_sink_t;
    friend class backfill_receiver_order_source_t;
    friend class plain_sink_t;
    friend class contiguous_order_sink_t;
};

/* Buckets are like file descriptors.  We don't want two order sources
   to have the same bucket, and we can reuse buckets when an order
   source is destroyed.  A pigeoncoop keeps track of all the available
   pigeonholes and what the initial value should be for the pigeon, I
   mean order source, that next gets assigned a given bucket. */
class order_source_pigeoncoop_t {
public:
#ifndef NDEBUG
    order_source_pigeoncoop_t(int starting_bucket = 0);
#else
    order_source_pigeoncoop_t(UNUSED int starting_bucket = 0) { }
#endif

    friend class order_source_t;
private:

    static void nop() { }

#ifndef NDEBUG
    void unregister_bucket(int bucket, int64_t counter);

    std::pair<int, int64_t> register_for_bucket();

    // The bucket we should use next, if free_buckets_ is empty.
    int least_unregistered_bucket_;

    // The buckets less than least_unregistered_bucket_ that are free.
    std::vector<std::pair<int, int64_t> > free_buckets_;
#endif

    DISABLE_COPYING(order_source_pigeoncoop_t);
};

/* Order sources create order tokens with increasing values for a
   specific bucket.  When they are destroyed they call a void()
   function which might inform somebody that the bucket is now
   available for reuse. */
class order_source_t {
public:
#ifndef NDEBUG
    order_source_t(int bucket = 0, boost::function<void()> unregisterator = order_source_pigeoncoop_t::nop);
    order_source_t(order_source_pigeoncoop_t *coop);
    ~order_source_t();

    order_token_t check_in(const std::string& tag);
#else
    order_source_t(UNUSED int bucket = 0, UNUSED boost::function<void()> unregisterator = order_source_pigeoncoop_t::nop) { }
    order_source_t(UNUSED order_source_pigeoncoop_t *coop) { }
    ~order_source_t() { }

    order_token_t check_in(const std::string&) { return order_token_t(); }
#endif  // ndef NDEBUG

private:
#ifndef NDEBUG
    int bucket_;
    int64_t counter_;
    boost::function<void ()> unregister_;
#endif  // ifndef NDEBUG

    DISABLE_COPYING(order_source_t);
};

/* A backfill receiver order source is a bit special, because when we
   backfill, we want backfill operations to get in before "realtime"
   operations.  So we play tricks with the counter depending on
   whether we're currently backfilling and whether we're checking in a
   backfill or a realtime operation.  (This assumes there will be no
   more than 4 billion backfill operations, which is ok for
   debugging purposes.)
 */
class backfill_receiver_order_source_t {
public:
#ifndef NDEBUG
    backfill_receiver_order_source_t(int bucket = BACKFILL_RECEIVER_ORDER_SOURCE_BUCKET);

    void backfill_begun();
    void backfill_done();

    order_token_t check_in_backfill_operation(const std::string& tag);
    order_token_t check_in_realtime_operation(const std::string& tag);
#else
    backfill_receiver_order_source_t(UNUSED int bucket = BACKFILL_RECEIVER_ORDER_SOURCE_BUCKET) { }

    void backfill_begun() { }
    void backfill_done() { }

    order_token_t check_in_backfill_operation(const std::string&) { return order_token_t(); }
    order_token_t check_in_realtime_operation(const std::string&) { return order_token_t(); }

#endif  // ifndef NDEBUG

private:

#ifndef NDEBUG
    int bucket_;
    int64_t counter_;
    bool backfill_active_;
#endif  // ifndef NDEBUG

    DISABLE_COPYING(backfill_receiver_order_source_t);
};

struct tagged_seen_t {
    int64_t value;
    std::string tag;

    tagged_seen_t(int64_t _value, const std::string& _tag) : value(_value), tag(_tag) { }
};

/* Eventually order tokens get to an order sink, and those of the same
   bucket had better arrive in the right order. */
class order_sink_t {
public:
#ifndef NDEBUG
    order_sink_t();

    void check_out(order_token_t token);
#else
    order_sink_t() { }

    void check_out(UNUSED  order_token_t token) { }

#endif  // ifndef NDEBUG

private:

#ifndef NDEBUG
    friend class plain_sink_t;
    static void verify_token_value_and_update(order_token_t token, std::pair<tagged_seen_t, tagged_seen_t> *ls_pair);

    // We keep two last seen values because reads can be reordered.
    // .first = last seen write, .second = max(last seen read, last seen write)
    std::vector<std::pair<tagged_seen_t, tagged_seen_t> > last_seens_;
#endif  // ifndef NDEBUG

    DISABLE_COPYING(order_sink_t);
};

// An order sink with less overhead, for situations where there is
// only one source (like the top of a btree slice) and many sinks.  If
// there's one bucket there's no point in instantiating a std::vector.
class plain_sink_t {
public:
#ifndef NDEBUG
    plain_sink_t();

    void check_out(order_token_t token);
#else
    plain_sink_t() { }

    void check_out(UNUSED  order_token_t token) { }
#endif  // ifndef NDEBUG

private:
#ifndef NDEBUG
    // The pair of last seen values.
    std::pair<tagged_seen_t, tagged_seen_t> ls_pair_;
#endif

    DISABLE_COPYING(plain_sink_t);
};

#endif  // __CONCURRENCY_FIFO_CHECKER_HPP__
<|endoftext|>


<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2019, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_config.h"
#include "condor_attributes.h"
#include "qmgmt.h"
#include "scheduler.h"
#include "condor_qmgr.h"
#include "jobsets.h"
#include "classad_merge.h"

// in schedd.cpp
void IncrementLiveJobCounter(LiveJobCounters & num, int universe, int status, int increment /*, JobQueueJob * job*/);

JobSets::JobSet::JobSet(int _id, std::string _name, std::string _owner, ClassAd *ad)
	: id(_id), name(_name), owner(_owner), setAd(ad)
{
	if (!setAd) {
		ClassAd ad;
		ad.EnableDirtyTracking();
		ad.Assign(ATTR_MY_TYPE, JOB_SET_ADTYPE);
		ad.Assign(ATTR_TARGET_TYPE, JOB_SET_ADTYPE);
		ad.Assign(ATTR_JOB_SET_NAME, name);
		ad.Assign(ATTR_JOB_SET_ID, id);
		ad.Assign(ATTR_OWNER, owner);
		JobSetStoreAllDirtyAttrs(id, ad, true);
	}
}

void
JobSets::setNextSetId(int id)
{
	next_setid_num = id;
	dprintf(D_FULLDEBUG, "JobSet setNextSetId restored to id %d\n", id);
}

void
JobSets::reconfig()
{

}

JobSets::~JobSets()
{
	// Deallocate each JobSet
	for (auto const & s : mapIdToSet) {
		delete s.second;
	}

}

bool
JobSets::restoreJobSet(ClassAd *setAd)
{
	int id = 0;
	std::string setName;
	std::string setOwner;

	if (!setAd->LookupInteger(ATTR_JOB_SET_ID, id) ||
		!setAd->LookupString(ATTR_OWNER, setOwner) ||
		!setAd->LookupString(ATTR_JOB_SET_NAME, setName))
	{
		dprintf(D_ALWAYS, "ERROR: restoreJobSet - log has malformed JobSet  (%s,%d)\n",
			setName.c_str(), id);
		return false;
	}

	// Add into our name to id map, making sure it is not already there
	unsigned int &setId = mapAliasToId[setOwner + setName];
	if (setId) {
		dprintf(D_ALWAYS, "ERROR: restoreJobSet - log has duplicate JobSet names (%s,%d)\n",
			setName.c_str(), setId);
		return false;
	}
	setId = id;

	// Add into our id to set object map, making sure it is not already there
	JobSet* &set = mapIdToSet[setId];
	if (set) {
		dprintf(D_ALWAYS, "ERROR: restoreJobSet - log has duplicate JobSet ids (%s,%d)\n",
			setName.c_str(), setId);
		return false;
	}
	set = new JobSet(setId, setName, setOwner, setAd);

	if (setId > next_setid_num) {
		dprintf(D_ALWAYS,"Warning: restoreJobSet - JobSet id larger than expected (%s,%d)\n",
			setName.c_str(), setId);
		next_setid_num = setId;
	}

	// Increment aggregates for removed and completed jobs from the past
	std::string prefix = "Scheduler";
	setAd->LookupInteger(ATTR_TOTAL_COMPLETED_JOBS, set->jobStatusAggregates.JobsCompleted);
	setAd->LookupInteger(prefix+ATTR_TOTAL_COMPLETED_JOBS, set->jobStatusAggregates.SchedulerJobsCompleted);
	setAd->LookupInteger(ATTR_TOTAL_REMOVED_JOBS, set->jobStatusAggregates.JobsRemoved);
	setAd->LookupInteger(prefix+ATTR_TOTAL_REMOVED_JOBS, set->jobStatusAggregates.SchedulerJobsRemoved);

	dprintf(D_FULLDEBUG, "Restored JobSet %s id=%d for owner %s\n",
		set->name.c_str(), set->id, set->owner.c_str());

	return true;
}

JobSets::JobSet* JobSets::getOrCreateSet(JobQueueJob & job)
{
	unsigned int setId = job.set_id;
	bool newSet = false;
	bool appendJobToSet = false;
	std::string setName;

	if (!setId) {
		appendJobToSet = true;
		// We have not yet added this job to any set
		if (!job.LookupString(ATTR_JOB_SET_NAME, setName)) {
			// default to cluster id...
			setName = std::to_string(job.jid.cluster);
		}
		std::string key = job.ownerinfo->name + setName;
		auto it = mapAliasToId.find(key);
		if (it == mapAliasToId.end()) {
			// Create a new set with a new set id!
			setId = ++next_setid_num;
			SetSecureAttributeInt(0, 0, ATTR_NEXT_JOBSET_NUM, setId);
			newSet = true;
			mapAliasToId[key] = setId;
		}
		else {
			// Appened this job to an existing set
			setId = it->second;
		}
	}

	JobSet* &set = mapIdToSet[setId];

	// Assert that mapAliasToID and mapIdToSet are in sync with each other
	ASSERT(newSet ? set==nullptr : set!=nullptr);

	if (newSet) {
		set = new JobSet(setId, setName, job.ownerinfo->name, nullptr);
		dprintf(D_ALWAYS, "Created new JobSet %s id=%d for owner %s\n",
			set->name.c_str(), set->id, set->owner.c_str());
	}

	if (appendJobToSet) {
		set->jobsInSet.insert(job.jid);
		job.Assign(ATTR_JOB_SET_ID, setId);
		job.set_id = setId;
	}

	if (!set->setAd) {
		// Note - it is still possible GetJobAd() will return a NULL here
		// if the set is being created as part of a transaction that has not yet
		// been committed.  So a NULL setAd should not be an error.
		set->setAd = GetJobAd(0, 0 - setId);
	}

	return set;
}

bool JobSets::removeSet(JobSet* & set)
{
	if (!set) return false;
	dprintf(D_ALWAYS, "Removing JobSet %s id=%d (%lu jobs) for owner %s\n",
		set->name.c_str(), set->id, set->jobsInSet.size(), set->owner.c_str());
	mapAliasToId.erase(set->owner + set->name);
	mapIdToSet.erase(set->id);
	bool ret = JobSetDestroy(set->id);
	if (!ret) {
		dprintf(D_ALWAYS, "WARNING: unable to remove from log JobSet %s id=%d (%lu jobs) for owner %s\n",
			set->name.c_str(), set->id, set->jobsInSet.size(), set->owner.c_str());
	}
	delete set;
	set = nullptr;  // set is destroyed, get rid of pointer to it
	return ret;
}

bool JobSets::update(JobQueueJob & job, int old_status, int new_status)
{
	if (old_status == new_status) {
		// nothing to do, since job status did not change
		return true;
	}

	JobSet * set = getOrCreateSet(job);

	if (!set) {
		// nothing to do, this job is not a member of a set
		return false;
	}

	IncrementLiveJobCounter(set->jobStatusAggregates, job.Universe(), old_status, -1);
	IncrementLiveJobCounter(set->jobStatusAggregates, job.Universe(), new_status, 1);

	if (IsDebugLevel(D_JOB) && old_status >= 0 ) {
		ClassAd s;
		set->jobStatusAggregates.publish(s, "Live");
		if (set->setAd) {
			MergeClassAds(&s, set->setAd, true);
		}
		dprintf(D_JOB, "Updating JobSet %s (id=%u) after status change in job %d.%d to be:\n",
			set->name.c_str(), set->id, job.jid.cluster, job.jid.proc);
		dPrintAd(D_JOB, s);
	}
	return true;
}

bool JobSets::removeJobFromSet(JobQueueJob & job)
{
	if (!job.set_id) return true;

	JobSet* jobset = getOrCreateSet(job);
	ASSERT(jobset);

	// update historical counters now to disk, as this job is leaving
	if (jobset->setAd) {
		std::string key;

		if (job.Status() == COMPLETED) {
			key = ATTR_TOTAL_COMPLETED_JOBS;
		}
		if (job.Status() == REMOVED) {
			key = ATTR_TOTAL_REMOVED_JOBS;
		}
		if (!key.empty()) {
			if (job.Universe() == CONDOR_UNIVERSE_SCHEDULER) {
				key = "Scheduler" + key;
			}
			int val = 0;
			jobset->setAd->LookupInteger(key, val);
			val++;
			jobset->setAd->Assign(key, val);
			jobset->dirty = true;
		}

		jobset->persistSetInfo();
	}

	jobset->jobsInSet.erase(job.jid);

	// Check if time to destroy this set...
	if (jobset->jobsInSet.size() == 0 &&
		jobset->garbagePolicy == garbagePolicyEnum::immediateAfterEmpty)
	{
		removeSet(jobset);
	}

	return true;
}

bool JobSets::JobSet::persistSetInfo()
{

	if (dirty) {
		dprintf(D_ALWAYS, "Updating JobSet %s id=%d (%lu jobs) for owner %s\n",
			name.c_str(), id, jobsInSet.size(), owner.c_str());

		if (!setAd) {
			setAd = GetJobAd(0, 0 - id);
		}
		ASSERT(setAd);

		JobSetStoreAllDirtyAttrs(id, *setAd, false);
	}

	dirty = false;

	return true;
}
<commit_msg>Remember if a job is not in any set to avoid ad lookups. #7227<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2019, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License.  You may
 * obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_config.h"
#include "condor_attributes.h"
#include "qmgmt.h"
#include "scheduler.h"
#include "condor_qmgr.h"
#include "jobsets.h"
#include "classad_merge.h"

// in schedd.cpp
void IncrementLiveJobCounter(LiveJobCounters & num, int universe, int status, int increment /*, JobQueueJob * job*/);

JobSets::JobSet::JobSet(int _id, std::string _name, std::string _owner, ClassAd *ad)
	: id(_id), name(_name), owner(_owner), setAd(ad)
{
	if (!setAd) {
		ClassAd ad;
		ad.EnableDirtyTracking();
		ad.Assign(ATTR_MY_TYPE, JOB_SET_ADTYPE);
		ad.Assign(ATTR_TARGET_TYPE, JOB_SET_ADTYPE);
		ad.Assign(ATTR_JOB_SET_NAME, name);
		ad.Assign(ATTR_JOB_SET_ID, id);
		ad.Assign(ATTR_OWNER, owner);
		JobSetStoreAllDirtyAttrs(id, ad, true);
	}
}

void
JobSets::setNextSetId(int id)
{
	next_setid_num = id;
	dprintf(D_FULLDEBUG, "JobSet setNextSetId restored to id %d\n", id);
}

void
JobSets::reconfig()
{

}

JobSets::~JobSets()
{
	// Deallocate each JobSet
	for (auto const & s : mapIdToSet) {
		delete s.second;
	}

}

bool
JobSets::restoreJobSet(ClassAd *setAd)
{
	int id = 0;
	std::string setName;
	std::string setOwner;

	if (!setAd->LookupInteger(ATTR_JOB_SET_ID, id) ||
		!setAd->LookupString(ATTR_OWNER, setOwner) ||
		!setAd->LookupString(ATTR_JOB_SET_NAME, setName))
	{
		dprintf(D_ALWAYS, "ERROR: restoreJobSet - log has malformed JobSet  (%s,%d)\n",
			setName.c_str(), id);
		return false;
	}

	// Add into our name to id map, making sure it is not already there
	unsigned int &setId = mapAliasToId[setOwner + setName];
	if (setId) {
		dprintf(D_ALWAYS, "ERROR: restoreJobSet - log has duplicate JobSet names (%s,%d)\n",
			setName.c_str(), setId);
		return false;
	}
	setId = id;

	// Add into our id to set object map, making sure it is not already there
	JobSet* &set = mapIdToSet[setId];
	if (set) {
		dprintf(D_ALWAYS, "ERROR: restoreJobSet - log has duplicate JobSet ids (%s,%d)\n",
			setName.c_str(), setId);
		return false;
	}
	set = new JobSet(setId, setName, setOwner, setAd);

	if (setId > next_setid_num) {
		dprintf(D_ALWAYS,"Warning: restoreJobSet - JobSet id larger than expected (%s,%d)\n",
			setName.c_str(), setId);
		next_setid_num = setId;
	}

	// Increment aggregates for removed and completed jobs from the past
	std::string prefix = "Scheduler";
	setAd->LookupInteger(ATTR_TOTAL_COMPLETED_JOBS, set->jobStatusAggregates.JobsCompleted);
	setAd->LookupInteger(prefix+ATTR_TOTAL_COMPLETED_JOBS, set->jobStatusAggregates.SchedulerJobsCompleted);
	setAd->LookupInteger(ATTR_TOTAL_REMOVED_JOBS, set->jobStatusAggregates.JobsRemoved);
	setAd->LookupInteger(prefix+ATTR_TOTAL_REMOVED_JOBS, set->jobStatusAggregates.SchedulerJobsRemoved);

	dprintf(D_FULLDEBUG, "Restored JobSet %s id=%d for owner %s\n",
		set->name.c_str(), set->id, set->owner.c_str());

	return true;
}

JobSets::JobSet* JobSets::getOrCreateSet(JobQueueJob & job)
{
	int setId = job.set_id;
	bool newSet = false;
	bool appendJobToSet = false;
	std::string setName;

	if (setId == -1) {
		// job is not in a set, bail out quickly now before ad lookups etc
		return nullptr;
	}

	if (setId == 0) {
		appendJobToSet = true;
		// We have not yet added this job to any set
		if (!job.LookupString(ATTR_JOB_SET_NAME, setName)) {
			// default to cluster id...
			setName = std::to_string(job.jid.cluster);
		}
		if (setName.empty()) {
			// remember this job is not in a set for fast bailout next time
			job.set_id = -1;
			return nullptr;
		}
		std::string key = job.ownerinfo->name + setName;
		auto it = mapAliasToId.find(key);
		if (it == mapAliasToId.end()) {
			// Create a new set with a new set id!
			setId = ++next_setid_num;
			SetSecureAttributeInt(0, 0, ATTR_NEXT_JOBSET_NUM, setId);
			newSet = true;
			mapAliasToId[key] = setId;
		}
		else {
			// Appened this job to an existing set
			setId = it->second;
		}
	}

	JobSet* &set = mapIdToSet[setId];

	// Assert that mapAliasToID and mapIdToSet are in sync with each other
	ASSERT(newSet ? set==nullptr : set!=nullptr);

	if (newSet) {
		set = new JobSet(setId, setName, job.ownerinfo->name, nullptr);
		dprintf(D_ALWAYS, "Created new JobSet %s id=%d for owner %s\n",
			set->name.c_str(), set->id, set->owner.c_str());
	}

	if (appendJobToSet) {
		set->jobsInSet.insert(job.jid);
		job.Assign(ATTR_JOB_SET_ID, setId);
		job.set_id = setId;
	}

	if (!set->setAd) {
		// Note - it is still possible GetJobAd() will return a NULL here
		// if the set is being created as part of a transaction that has not yet
		// been committed.  So a NULL setAd should not be an error.
		set->setAd = GetJobAd(0, 0 - setId);
	}

	return set;
}

bool JobSets::removeSet(JobSet* & set)
{
	if (!set) return false;
	dprintf(D_ALWAYS, "Removing JobSet %s id=%d (%lu jobs) for owner %s\n",
		set->name.c_str(), set->id, set->jobsInSet.size(), set->owner.c_str());
	mapAliasToId.erase(set->owner + set->name);
	mapIdToSet.erase(set->id);
	bool ret = JobSetDestroy(set->id);
	if (!ret) {
		dprintf(D_ALWAYS, "WARNING: unable to remove from log JobSet %s id=%d (%lu jobs) for owner %s\n",
			set->name.c_str(), set->id, set->jobsInSet.size(), set->owner.c_str());
	}
	delete set;
	set = nullptr;  // set is destroyed, get rid of pointer to it
	return ret;
}

bool JobSets::update(JobQueueJob & job, int old_status, int new_status)
{
	if (old_status == new_status) {
		// nothing to do, since job status did not change
		return true;
	}

	if (job.set_id <= 0) {
		// If this job has not yet been placed into a set, then do not decrement
		// job counters for leaving the old_status.
		old_status = -1;
	}

	JobSet * set = getOrCreateSet(job);

	if (!set) {
		// nothing to do, this job is not a member of a set
		return false;
	}

	IncrementLiveJobCounter(set->jobStatusAggregates, job.Universe(), old_status, -1);
	IncrementLiveJobCounter(set->jobStatusAggregates, job.Universe(), new_status, 1);

	if (IsDebugLevel(D_JOB) && old_status >= 0 ) {
		ClassAd s;
		set->jobStatusAggregates.publish(s, "Live");
		if (set->setAd) {
			MergeClassAds(&s, set->setAd, true);
		}
		dprintf(D_JOB, "Updating JobSet %s (id=%u) after status change in job %d.%d to be:\n",
			set->name.c_str(), set->id, job.jid.cluster, job.jid.proc);
		dPrintAd(D_JOB, s);
	}
	return true;
}

bool JobSets::removeJobFromSet(JobQueueJob & job)
{
	if (job.set_id <= 0) return true;

	JobSet* jobset = getOrCreateSet(job);
	ASSERT(jobset);

	// update historical counters now to disk, as this job is leaving
	if (jobset->setAd) {
		std::string key;

		if (job.Status() == COMPLETED) {
			key = ATTR_TOTAL_COMPLETED_JOBS;
		}
		if (job.Status() == REMOVED) {
			key = ATTR_TOTAL_REMOVED_JOBS;
		}
		if (!key.empty()) {
			if (job.Universe() == CONDOR_UNIVERSE_SCHEDULER) {
				key = "Scheduler" + key;
			}
			int val = 0;
			jobset->setAd->LookupInteger(key, val);
			val++;
			jobset->setAd->Assign(key, val);
			jobset->dirty = true;
		}

		jobset->persistSetInfo();
	}

	jobset->jobsInSet.erase(job.jid);
	job.set_id = -1;

	// Check if time to destroy this set...
	if (jobset->jobsInSet.size() == 0 &&
		jobset->garbagePolicy == garbagePolicyEnum::immediateAfterEmpty)
	{
		removeSet(jobset);
	}

	return true;
}

bool JobSets::JobSet::persistSetInfo()
{

	if (dirty) {
		dprintf(D_ALWAYS, "Updating JobSet %s id=%d (%lu jobs) for owner %s\n",
			name.c_str(), id, jobsInSet.size(), owner.c_str());

		if (!setAd) {
			setAd = GetJobAd(0, 0 - id);
		}
		ASSERT(setAd);

		JobSetStoreAllDirtyAttrs(id, *setAd, false);
	}

	dirty = false;

	return true;
}
<|endoftext|>


<commit_before>/*
 *  _____             ___ ___   |
 * |  _  |___ ___ _ _|_  |_  |  |  C/C++ framework for 32-bit AVRs
 * |     | -_|  _| | |_  |  _|  |
 * |__|__|___|_| |_  |___|___|  |  https://github.com/aery32
 *               |___|          |
 *
 * Copyright (c) 2012, Muiku Oy
 * All rights reserved.
 *
 * LICENSE
 *
 * New BSD License, see the LICENSE.txt bundled with this package. If you did
 * not receive a copy of the license and are unable to obtain it through the
 * world-wide-web, please send an email to contact@muiku.com so we can send
 * you a copy.
 */

#include "aery32/twi.h"

namespace aery {
	volatile avr32_twi_t *twi = &AVR32_TWI;
	volatile uint32_t __twi_lsr = AVR32_TWI.sr;
}

#define TWI_WAIT_TO_COMPLETE() do { \
	while ((aery::__twi_lsr & AVR32_TWI_SR_TXCOMP_MASK) == 0) \
		aery::__twi_lsr = aery::twi->sr; \
} while (0)

void aery::twi_init_master(void)
{
	/* Software reset. */
	aery::twi->CR.swrst = 1;
	while (aery::twi->CR.swrst);

	/* Setup SLK to 100 kHz by default with 50% duty cycle */
	aery::twi_setup_clkwaveform(4, 0x3f, 0x3f);
	aery::twi_clear_internal_address();

	/* Disable slave mode and enable as master */
	aery::twi->CR.svdis = 1;
	aery::twi->CR.msen = 1;
}

// void aery::twi_init_slave(uint16_t sla)
// {
// 	/* Software reset. */
// 	aery::twi->CR.swrst = 1;
// 	while (aery::twi->CR.swrst);

// 	/* Disable master mode and enable as slave with SLA */
// 	aery::twi->SMR.sadr = sla;
// 	aery::twi->CR.msdis = 1;
// 	aery::twi->CR.sven = 1;
// }

void aery::twi_setup_clkwaveform(uint8_t ckdiv, uint8_t cldiv, uint8_t chdiv)
{
	aery::twi->CWGR.ckdiv = ckdiv;
	aery::twi->CWGR.cldiv = cldiv;
	aery::twi->CWGR.chdiv = chdiv;
}

void aery::twi_select_slave(uint16_t sla)
{
	aery::twi->MMR.dadr = sla;
}

void aery::twi_use_internal_address(uint32_t iadr, uint8_t n)
{
	aery::twi->IADR.iadr = iadr;
	aery::twi->MMR.iadrsz = n;
}

void aery::twi_clear_internal_address(void)
{
	aery::twi_use_internal_address(0, 0);
}

size_t aery::twi_read_nbytes(uint8_t *data, size_t n)
{
	using namespace aery;
	size_t i = 0;

	if (n == 1)
		return twi_read_byte(data);

begin:
	/* Switch to read mode */
	twi->MMR.mread = 1;

	/* Start multiple byte read operation */
	twi->cr |= AVR32_TWI_CR_START_MASK;

	/* Check arbitration */
	if (((__twi_lsr = twi->sr) & AVR32_TWI_SR_ARBLST_MASK) != 0)
		goto begin;

	for (; i < n - 1; i++) {
		while (twi_isbusy());
		if ((__twi_lsr & AVR32_TWI_SR_NACK_MASK) != 0)
			goto error;
		data[i] = twi->RHR.rxdata;
	}

	/* Send STOP */
	twi->cr |= AVR32_TWI_CR_STOP_MASK;

	/* Read last byte */
	while (twi_isbusy());
	if ((__twi_lsr & AVR32_TWI_SR_NACK_MASK) == 0)
		data[++i] = twi->RHR.rxdata;

	TWI_WAIT_TO_COMPLETE();
	return i;

error:
	twi->cr |= AVR32_TWI_CR_STOP_MASK;
	TWI_WAIT_TO_COMPLETE();
	return i;
}

size_t aery::twi_read_nbytes(uint8_t *data, size_t n, uint8_t iadr,
		uint8_t iadrlen)
{
	aery::twi_use_internal_address(iadr, iadrlen);
	return aery::twi_read_nbytes(data, n);
}

size_t aery::twi_read_byte(uint8_t *data)
{
	size_t i = 0;

	/* Switch to read mode */
	aery::twi->MMR.mread = 1;

	/* Start one byte read operation */
	aery::twi->cr |= AVR32_TWI_CR_START_MASK | AVR32_TWI_CR_STOP_MASK;

	while (aery::twi_isbusy());
	if ((aery::__twi_lsr & AVR32_TWI_SR_NACK_MASK) == 0)
		data[i++] = aery::twi->RHR.rxdata;

	TWI_WAIT_TO_COMPLETE();
	return i;
}

size_t aery::twi_read_byte(uint8_t *data, uint8_t iadr, uint8_t iadrlen)
{
	aery::twi_use_internal_address(iadr, iadrlen);
	return aery::twi_read_byte(data);
}

size_t aery::twi_write_nbytes(uint8_t *data, size_t n)
{
	size_t i = 0;

	/* Switch to write mode */
	aery::twi->MMR.mread = 0;

	for (; i < n; i++) {
		aery::twi->THR.txdata = *data;
		while (aery::twi_isbusy());
		if ((aery::__twi_lsr & AVR32_TWI_SR_NACK_MASK) != 0)
			break;
	}

	TWI_WAIT_TO_COMPLETE();
	return i;
}

size_t aery::twi_write_nbytes(uint8_t *data, size_t n, uint8_t iadr,
		uint8_t iadrlen)
{
	aery::twi_use_internal_address(iadr, iadrlen);
	return aery::twi_write_nbytes(data, n);
}

size_t aery::twi_write_byte(uint8_t data)
{
	return aery::twi_write_nbytes(&data, 1);
}

size_t aery::twi_write_byte(uint8_t data, uint8_t iadr, uint8_t iadrlen)
{
	return aery::twi_write_nbytes(&data, 1, iadr, iadrlen);
}

bool aery::twi_isbusy(void)
{
	aery::__twi_lsr = aery::twi->sr;
	if (aery::twi->MMR.mread == 1)
		return (aery::__twi_lsr & AVR32_TWI_SR_RXRDY_MASK) == 0;
	return (aery::__twi_lsr & AVR32_TWI_SR_TXRDY_MASK) == 0;
}

bool aery::twi_is_enabled()
{
	#define TWI_PINS ((1 << 29) | (1 << 30))
	volatile avr32_gpio_port_t *twi_port = &AVR32_GPIO.port[0];

	/*
	 * TWI is enabled when dedicate TWD and TWCK have been assigned to
	 * the peripheral lines and defined to be as open-drain. */
	if ((twi_port->gper & TWI_PINS) != 0)
		return false;
	if ((twi_port->pmr0 & TWI_PINS) != 0)
		return false;
	if ((twi_port->pmr1 & TWI_PINS) != 0)
		return false;
	if ((twi_port->odmer & TWI_PINS) != 0)
		return false;
	return true;
}

bool aery::twi_has_overrun(bool reread)
{
	if (reread)
		aery::__twi_lsr = aery::twi->sr;
	return (aery::__twi_lsr & AVR32_TWI_SR_OVRE_MASK) != 0;
}<commit_msg>Fix (workaround) to reset TWI RXRDY flag<commit_after>/*
 *  _____             ___ ___   |
 * |  _  |___ ___ _ _|_  |_  |  |  C/C++ framework for 32-bit AVRs
 * |     | -_|  _| | |_  |  _|  |
 * |__|__|___|_| |_  |___|___|  |  https://github.com/aery32
 *               |___|          |
 *
 * Copyright (c) 2012, Muiku Oy
 * All rights reserved.
 *
 * LICENSE
 *
 * New BSD License, see the LICENSE.txt bundled with this package. If you did
 * not receive a copy of the license and are unable to obtain it through the
 * world-wide-web, please send an email to contact@muiku.com so we can send
 * you a copy.
 */

#include "aery32/twi.h"

namespace aery {
	volatile avr32_twi_t *twi = &AVR32_TWI;
	volatile uint32_t __twi_lsr = AVR32_TWI.sr;
}

#define TWI_WAIT_TO_COMPLETE() do { \
	while ((aery::__twi_lsr & AVR32_TWI_SR_TXCOMP_MASK) == 0) \
		aery::__twi_lsr = aery::twi->sr; \
} while (0)

void aery::twi_init_master(void)
{
	/* Software reset. */
	aery::twi->CR.swrst = 1;
	while (aery::twi->CR.swrst);

	/* See errata, datahseet p. 794 */
	volatile uint32_t rhr = aery::twi->rhr;

	/* Setup SLK to 100 kHz by default with 50% duty cycle */
	aery::twi_setup_clkwaveform(4, 0x3f, 0x3f);
	aery::twi_clear_internal_address();

	/* Disable slave mode and enable as master */
	aery::twi->CR.svdis = 1;
	aery::twi->CR.msen = 1;
}

// void aery::twi_init_slave(uint16_t sla)
// {
// 	/* Software reset. */
// 	aery::twi->CR.swrst = 1;
// 	while (aery::twi->CR.swrst);

// 	/* Disable master mode and enable as slave with SLA */
// 	aery::twi->SMR.sadr = sla;
// 	aery::twi->CR.msdis = 1;
// 	aery::twi->CR.sven = 1;
// }

void aery::twi_setup_clkwaveform(uint8_t ckdiv, uint8_t cldiv, uint8_t chdiv)
{
	aery::twi->CWGR.ckdiv = ckdiv;
	aery::twi->CWGR.cldiv = cldiv;
	aery::twi->CWGR.chdiv = chdiv;
}

void aery::twi_select_slave(uint16_t sla)
{
	aery::twi->MMR.dadr = sla;
}

void aery::twi_use_internal_address(uint32_t iadr, uint8_t n)
{
	aery::twi->IADR.iadr = iadr;
	aery::twi->MMR.iadrsz = n;
}

void aery::twi_clear_internal_address(void)
{
	aery::twi_use_internal_address(0, 0);
}

size_t aery::twi_read_nbytes(uint8_t *data, size_t n)
{
	using namespace aery;
	size_t i = 0;

	if (n == 1)
		return twi_read_byte(data);

begin:
	/* Switch to read mode */
	twi->MMR.mread = 1;

	/* Start multiple byte read operation */
	twi->cr |= AVR32_TWI_CR_START_MASK;

	/* Check arbitration */
	if (((__twi_lsr = twi->sr) & AVR32_TWI_SR_ARBLST_MASK) != 0)
		goto begin;

	for (; i < n - 1; i++) {
		while (twi_isbusy());
		if ((__twi_lsr & AVR32_TWI_SR_NACK_MASK) != 0)
			goto error;
		data[i] = twi->RHR.rxdata;
	}

	/* Send STOP */
	twi->cr |= AVR32_TWI_CR_STOP_MASK;

	/* Read last byte */
	while (twi_isbusy());
	if ((__twi_lsr & AVR32_TWI_SR_NACK_MASK) == 0)
		data[++i] = twi->RHR.rxdata;

	TWI_WAIT_TO_COMPLETE();
	return i;

error:
	twi->cr |= AVR32_TWI_CR_STOP_MASK;
	TWI_WAIT_TO_COMPLETE();
	return i;
}

size_t aery::twi_read_nbytes(uint8_t *data, size_t n, uint8_t iadr,
		uint8_t iadrlen)
{
	aery::twi_use_internal_address(iadr, iadrlen);
	return aery::twi_read_nbytes(data, n);
}

size_t aery::twi_read_byte(uint8_t *data)
{
	size_t i = 0;

	/* Switch to read mode */
	aery::twi->MMR.mread = 1;

	/* Start one byte read operation */
	aery::twi->cr |= AVR32_TWI_CR_START_MASK | AVR32_TWI_CR_STOP_MASK;

	while (aery::twi_isbusy());
	if ((aery::__twi_lsr & AVR32_TWI_SR_NACK_MASK) == 0)
		data[i++] = aery::twi->RHR.rxdata;

	TWI_WAIT_TO_COMPLETE();
	return i;
}

size_t aery::twi_read_byte(uint8_t *data, uint8_t iadr, uint8_t iadrlen)
{
	aery::twi_use_internal_address(iadr, iadrlen);
	return aery::twi_read_byte(data);
}

size_t aery::twi_write_nbytes(uint8_t *data, size_t n)
{
	size_t i = 0;

	/* Switch to write mode */
	aery::twi->MMR.mread = 0;

	for (; i < n; i++) {
		aery::twi->THR.txdata = *data;
		while (aery::twi_isbusy());
		if ((aery::__twi_lsr & AVR32_TWI_SR_NACK_MASK) != 0)
			break;
	}

	TWI_WAIT_TO_COMPLETE();
	return i;
}

size_t aery::twi_write_nbytes(uint8_t *data, size_t n, uint8_t iadr,
		uint8_t iadrlen)
{
	aery::twi_use_internal_address(iadr, iadrlen);
	return aery::twi_write_nbytes(data, n);
}

size_t aery::twi_write_byte(uint8_t data)
{
	return aery::twi_write_nbytes(&data, 1);
}

size_t aery::twi_write_byte(uint8_t data, uint8_t iadr, uint8_t iadrlen)
{
	return aery::twi_write_nbytes(&data, 1, iadr, iadrlen);
}

bool aery::twi_isbusy(void)
{
	aery::__twi_lsr = aery::twi->sr;
	if (aery::twi->MMR.mread == 1)
		return (aery::__twi_lsr & AVR32_TWI_SR_RXRDY_MASK) == 0;
	return (aery::__twi_lsr & AVR32_TWI_SR_TXRDY_MASK) == 0;
}

bool aery::twi_is_enabled()
{
	#define TWI_PINS ((1 << 29) | (1 << 30))
	volatile avr32_gpio_port_t *twi_port = &AVR32_GPIO.port[0];

	/*
	 * TWI is enabled when dedicate TWD and TWCK have been assigned to
	 * the peripheral lines and defined to be as open-drain. */
	if ((twi_port->gper & TWI_PINS) != 0)
		return false;
	if ((twi_port->pmr0 & TWI_PINS) != 0)
		return false;
	if ((twi_port->pmr1 & TWI_PINS) != 0)
		return false;
	if ((twi_port->odmer & TWI_PINS) != 0)
		return false;
	return true;
}

bool aery::twi_has_overrun(bool reread)
{
	if (reread)
		aery::__twi_lsr = aery::twi->sr;
	return (aery::__twi_lsr & AVR32_TWI_SR_OVRE_MASK) != 0;
}<|endoftext|>


<commit_before><commit_msg>add generic reference counting class<commit_after><|endoftext|>


<commit_before>#include "Symbol.h"
#include "Shape.h"
#include "FileIO.h"
#include "Sprite.h"
#include "ShapeFactory.h"

namespace emesh
{

Symbol::Symbol()
	: m_image(NULL)
	, m_shape(NULL)
	, m_pause(false)
{
}

Symbol::Symbol(const Symbol& s)
	: d2d::ISymbol(s)
{
	s.m_image->retain();
	m_image = s.m_image;

	m_shape = s.m_shape->clone();
}

Symbol::Symbol(d2d::Image* image)
{
	image->retain();
	m_image = image;

	m_shape = ShapeFactory::Instance()->CreateShape(*image);
}

Symbol::~Symbol()
{
	if (m_image)
	{
		m_image->release();
		m_image = NULL;
	}
	if (m_shape)
	{
		m_shape->release();
		m_shape = NULL;
	}
}

Symbol* Symbol::clone() const
{
	return new Symbol(*this);
}

void Symbol::reloadTexture() const
{
	m_image->reload();
}

void Symbol::draw(const d2d::Screen& scr,
				  const d2d::Matrix& mt,
				  const d2d::Colorf& mul,
				  const d2d::Colorf& add,
				  const d2d::ISprite* sprite) const
{
 	if (m_shape) {
 		d2d::ShaderNew* shader = d2d::ShaderNew::Instance();
 		shader->sprite();
		shader->SetSpriteColor(mul, add);

 		m_shape->DrawTexture(scr, mt);
  		if (!m_pause && sprite)
		{
			const Sprite* s = static_cast<const Sprite*>(sprite);
  			d2d::Vector spd = s->GetSpeed();
  			if (spd.x != 0 || spd.y != 0) {
  				m_shape->OffsetUV(spd.x, spd.y);
  			}
  		}
 	}
}

// d2d::Rect Symbol::getSize(const d2d::ISprite* sprite) const
// {
// //	return m_image->getRegion();
// }

void Symbol::SetShape(Shape* shape)
{
	if (m_shape) {
		m_shape->release();
	}
	shape->retain();
	m_shape = shape;
}

const wxString& Symbol::GetImagePath() const
{
	return m_image->filepath();
}

void Symbol::LoadImage(const wxString& filepath)
{
//	d2d::BitmapMgr::Instance()->getItem(filepath, &m_bitmap);
	d2d::ImageMgr::Instance()->getItem(filepath, &m_image);
}

int Symbol::GetQuadSize() const
{
	return m_shape->GetQuadSize();
}

void Symbol::loadResources()
{
	FileIO::load(m_filepath, this);
	InitBounding();
}

void Symbol::InitBounding()
{
	m_region = m_shape->GetRegion();
}

}<commit_msg>[FIXED] mesh symbol reloadTexture时空指针<commit_after>#include "Symbol.h"
#include "Shape.h"
#include "FileIO.h"
#include "Sprite.h"
#include "ShapeFactory.h"

namespace emesh
{

Symbol::Symbol()
	: m_image(NULL)
	, m_shape(NULL)
	, m_pause(false)
{
}

Symbol::Symbol(const Symbol& s)
	: d2d::ISymbol(s)
{
	s.m_image->retain();
	m_image = s.m_image;

	m_shape = s.m_shape->clone();
}

Symbol::Symbol(d2d::Image* image)
{
	image->retain();
	m_image = image;

	m_shape = ShapeFactory::Instance()->CreateShape(*image);
}

Symbol::~Symbol()
{
	if (m_image)
	{
		m_image->release();
		m_image = NULL;
	}
	if (m_shape)
	{
		m_shape->release();
		m_shape = NULL;
	}
}

Symbol* Symbol::clone() const
{
	return new Symbol(*this);
}

void Symbol::reloadTexture() const
{
	if (m_image) {
		m_image->reload();
	}
}

void Symbol::draw(const d2d::Screen& scr,
				  const d2d::Matrix& mt,
				  const d2d::Colorf& mul,
				  const d2d::Colorf& add,
				  const d2d::ISprite* sprite) const
{
 	if (m_shape) {
 		d2d::ShaderNew* shader = d2d::ShaderNew::Instance();
 		shader->sprite();
		shader->SetSpriteColor(mul, add);

 		m_shape->DrawTexture(scr, mt);
  		if (!m_pause && sprite)
		{
			const Sprite* s = static_cast<const Sprite*>(sprite);
  			d2d::Vector spd = s->GetSpeed();
  			if (spd.x != 0 || spd.y != 0) {
  				m_shape->OffsetUV(spd.x, spd.y);
  			}
  		}
 	}
}

// d2d::Rect Symbol::getSize(const d2d::ISprite* sprite) const
// {
// //	return m_image->getRegion();
// }

void Symbol::SetShape(Shape* shape)
{
	if (m_shape) {
		m_shape->release();
	}
	shape->retain();
	m_shape = shape;
}

const wxString& Symbol::GetImagePath() const
{
	return m_image->filepath();
}

void Symbol::LoadImage(const wxString& filepath)
{
//	d2d::BitmapMgr::Instance()->getItem(filepath, &m_bitmap);
	d2d::ImageMgr::Instance()->getItem(filepath, &m_image);
}

int Symbol::GetQuadSize() const
{
	return m_shape->GetQuadSize();
}

void Symbol::loadResources()
{
	FileIO::load(m_filepath, this);
	InitBounding();
}

void Symbol::InitBounding()
{
	m_region = m_shape->GetRegion();
}

}<|endoftext|>


<commit_before>/*
 * MomentumConn.cpp
 *
 *  Created on: Feburary 27, 2014
 *      Author: slundquist
 */

#include "MomentumConn.hpp"
#include <cstring>

namespace PV {

MomentumConn::MomentumConn(){
   initialize_base();
}

MomentumConn::MomentumConn(const char * name, HyPerCol * hc, InitWeights * weightInitializer, NormalizeBase * weightNormalizer) : HyPerConn()
{
   initialize_base();
   initialize(name, hc, weightInitializer, weightNormalizer);
}

MomentumConn::~MomentumConn() {
   if(momentumMethod){
      free(momentumMethod);
   }
}

int MomentumConn::initialize_base() {
   prev_dwDataStart = NULL;
   momentumTau = .25;
   momentumMethod = NULL;
   momentumDecay = 0;
   return PV_SUCCESS;
}

int MomentumConn::allocateDataStructures(){
   HyPerConn::allocateDataStructures();
   if (!plasticityFlag) return PV_SUCCESS;
   int sx = nfp;
   int sy = sx * nxp;
   int sp = sy * nyp;
   int nPatches = getNumDataPatches();

   const int numAxons = numberOfAxonalArborLists();

   //Allocate dw buffer for previous dw
   prev_dwDataStart = (pvwdata_t **) calloc(numAxons, sizeof(pvwdata_t *));
   if( prev_dwDataStart == NULL ) {
      createArborsOutOfMemory();
      assert(false);
   }
   prev_dwDataStart[0] = (pvwdata_t*) calloc(numAxons * nxp * nyp * nfp * nPatches, sizeof(pvwdata_t));
   assert(prev_dwDataStart[0] != NULL);
   for (int arborId = 0; arborId < numAxons; arborId++) {
      prev_dwDataStart[arborId] = (prev_dwDataStart[0] + sp * nPatches * arborId);
      assert(prev_dwDataStart[arborId] != NULL);
   } // loop over arbors

   return PV_SUCCESS;
}

int MomentumConn::ioParamsFillGroup(enum ParamsIOFlag ioFlag) {
   int status = HyPerConn::ioParamsFillGroup(ioFlag);
   ioParam_momentumTau(ioFlag);
   ioParam_momentumMethod(ioFlag);
   ioParam_momentumDecay(ioFlag);
   return status;
}

void MomentumConn::ioParam_momentumTau(enum ParamsIOFlag ioFlag){
   if(plasticityFlag){
      parent->ioParamValue(ioFlag, name, "momentumTau", &momentumTau, momentumTau);
   }
}

/**
 * @brief momentumMethod: The momentum method to use
 * @details Assuming a = dwMax * pre * post
 * simple: deltaW(t) = a + momentumTau * deltaW(t-1)
 * viscosity: deltaW(t) = momentumTau * (deltaW(t-1) + a) * (1-e^(-deltaT/momentumTau))
 * alex: deltaW(t) = momentumTau * delta(t-1) - momentumDecay * dwMax * w(t) - a
 */
void MomentumConn::ioParam_momentumMethod(enum ParamsIOFlag ioFlag){
   if(plasticityFlag){
      parent->ioParamStringRequired(ioFlag, name, "momentumMethod", &momentumMethod);
      if(strcmp(momentumMethod, "simple") != 0 &&
         strcmp(momentumMethod, "viscosity") != 0 &&
         strcmp(momentumMethod, "alex")){
         std::cout << "MomentumConn " << name << ": momentumMethod of " << momentumMethod << " is not known, options are \"simple\", \"viscosity\", and \"alex\"\n";
         exit(-1);
      }
   }
}

void MomentumConn::ioParam_momentumDecay(enum ParamsIOFlag ioFlag){
   if(plasticityFlag){
      parent->ioParamValue(ioFlag, name, "momentumDecay", &momentumDecay, momentumDecay);
      if(momentumDecay < 0 || momentumDecay > 1){
         std::cout << "MomentumConn " << name << ": momentumDecay must be between 0 and 1 inclusive\n";
         exit(-1);
      }
   }
}

//Copied from HyPerConn, only change is a memcpy from dwweights to prev_dwweights
int MomentumConn::updateState(double time, double dt){
   int status = PV_SUCCESS;
   if( !plasticityFlag ) {
      return status;
   }
   update_timer->start();

   if (!combine_dW_with_W_flag) { clear_dW(); }
   for(int arborId=0;arborId<numberOfAxonalArborLists();arborId++) {
      status = calc_dW(arborId);        // Calculate changes in weights
      if (status==PV_BREAK) { break; }
      assert(status == PV_SUCCESS);
   }

   bool needSynchronizing = keepKernelsSynchronized_flag;
   needSynchronizing |= sharedWeights && (parent->simulationTime() >= parent->getStopTime()-parent->getDeltaTime());
   if (needSynchronizing) {
      for (int arborID = 0; arborID < numberOfAxonalArborLists(); arborID++) {
         status = reduceKernels(arborID); // combine partial changes in each column
         if (status == PV_BREAK) {
            break;
         }
         assert(status == PV_SUCCESS);
      }
   }

   //Apply momentum
   for (int arborID = 0; arborID < numberOfAxonalArborLists(); arborID++) {
      status = applyMomentum(arborID);
      if (status == PV_BREAK) {
         break;
      }
      assert(status == PV_SUCCESS);
   }

   //Update prev_dwData buffer
   assert(prev_dwDataStart);
   //After reduce, copy over to prev_dwData
   std::memcpy(*prev_dwDataStart, *get_dwDataStart(),
         sizeof(pvwdata_t) *
         numberOfAxonalArborLists() *
         nxp * nyp * nfp *
         getNumDataPatches());

   for(int arborId=0;arborId<numberOfAxonalArborLists();arborId++){
      status = updateWeights(arborId);  // Apply changes in weights
      if (status==PV_BREAK) { break; }
      assert(status==PV_SUCCESS);
   }
   // normalizeWeights(); // normalizeWeights call moved to HyPerCol::advanceTime loop, to allow for normalization of a group of connections

   update_timer->stop();
   return status;
}

int MomentumConn::applyMomentum(int arbor_ID){
   int nExt = preSynapticLayer()->getNumExtended();
   const PVLayerLoc * loc = preSynapticLayer()->getLayerLoc();
   if(sharedWeights){
      int numKernels = getNumDataPatches();
      //Shared weights done in parallel, parallel in numkernels
#ifdef PV_USE_OPENMP_THREADS
#pragma omp parallel for
#endif
      for(int kernelIdx = 0; kernelIdx < numKernels; kernelIdx++){
         pvwdata_t * dwdata_start  = get_dwDataHead(arbor_ID, kernelIdx);
         pvwdata_t * prev_dw_start = get_prev_dwDataHead(arbor_ID, kernelIdx);
         pvwdata_t * wdata_start   = get_wData(arbor_ID, kernelIdx);
         if(!strcmp(momentumMethod, "simple")){
            for(int k = 0; k < nxp*nyp*nfp; k++){
               dwdata_start[k] += momentumTau * prev_dw_start[k] - momentumDecay*wdata_start[k];
            }
         }
         else if(!strcmp(momentumMethod, "viscosity")){
            for(int k = 0; k < nxp*nyp*nfp; k++){
               dwdata_start[k] = momentumTau * (prev_dw_start[k] + dwdata_start[k]) * (1 - exp(- parent->getDeltaTime() / momentumTau)) - momentumDecay*wdata_start[k];
            }
         }
         else if(!strcmp(momentumMethod, "alex")){
            for(int k = 0; k < nxp*nyp*nfp; k++){
               dwdata_start[k] = momentumTau * prev_dw_start[k] - (1-momentumDecay) * getDWMax()* wdata_start[k] - dwdata_start[k];
            }
         }
      }
   }
   else{
      std::cout << "Momentum not implemented for non-shared weights\n";
      exit(-1);
   }
   return PV_SUCCESS;
}

int MomentumConn::checkpointWrite(const char * cpDir) {
   HyPerConn::checkpointWrite(cpDir);
   if (!plasticityFlag) return PV_SUCCESS;
   char filename[PV_PATH_MAX];
   int chars_needed = snprintf(filename, PV_PATH_MAX, "%s/%s_prev_dW.pvp", cpDir, name);
   if(chars_needed >= PV_PATH_MAX) {
      if ( parent->icCommunicator()->commRank()==0 ) {
         fprintf(stderr, "HyPerConn::checkpointFilename error: path \"%s/%s_W.pvp\" is too long.\n", cpDir, name);
      }
      abort();
   }
   PVPatch *** patches_arg = sharedWeights ? NULL : get_wPatches();
   int status = writeWeights(patches_arg, prev_dwDataStart, getNumDataPatches(), filename, parent->simulationTime(), writeCompressedCheckpoints, /*last*/true);
   assert(status==PV_SUCCESS);
   return PV_SUCCESS;
}

int MomentumConn::checkpointRead(const char * cpDir, double * timeptr) {
   HyPerConn::checkpointRead(cpDir, timeptr);
   if (!plasticityFlag) return PV_SUCCESS;
   clearWeights(prev_dwDataStart, getNumDataPatches(), nxp, nyp, nfp);
   char * path = parent->pathInCheckpoint(cpDir, getName(), "_prev_dW.pvp");
   PVPatch *** patches_arg = sharedWeights ? NULL : get_wPatches();
   double filetime=0.0;
   int status = PV::readWeights(patches_arg, prev_dwDataStart, numberOfAxonalArborLists(), getNumDataPatches(), nxp, nyp, nfp, path, parent->icCommunicator(), &filetime, pre->getLayerLoc());
   if (parent->columnId()==0 && timeptr && *timeptr != filetime) {
      fprintf(stderr, "Warning: \"%s\" checkpoint has timestamp %g instead of the expected value %g.\n", path, filetime, *timeptr);
   }
   free(path);
   return status;
}

} // end namespace PV
<commit_msg>Fixed a bug with momentumConn and grabbing wrong weight<commit_after>/*
 * MomentumConn.cpp
 *
 *  Created on: Feburary 27, 2014
 *      Author: slundquist
 */

#include "MomentumConn.hpp"
#include <cstring>

namespace PV {

MomentumConn::MomentumConn(){
   initialize_base();
}

MomentumConn::MomentumConn(const char * name, HyPerCol * hc, InitWeights * weightInitializer, NormalizeBase * weightNormalizer) : HyPerConn()
{
   initialize_base();
   initialize(name, hc, weightInitializer, weightNormalizer);
}

MomentumConn::~MomentumConn() {
   if(momentumMethod){
      free(momentumMethod);
   }
}

int MomentumConn::initialize_base() {
   prev_dwDataStart = NULL;
   momentumTau = .25;
   momentumMethod = NULL;
   momentumDecay = 0;
   return PV_SUCCESS;
}

int MomentumConn::allocateDataStructures(){
   HyPerConn::allocateDataStructures();
   if (!plasticityFlag) return PV_SUCCESS;
   int sx = nfp;
   int sy = sx * nxp;
   int sp = sy * nyp;
   int nPatches = getNumDataPatches();

   const int numAxons = numberOfAxonalArborLists();

   //Allocate dw buffer for previous dw
   prev_dwDataStart = (pvwdata_t **) calloc(numAxons, sizeof(pvwdata_t *));
   if( prev_dwDataStart == NULL ) {
      createArborsOutOfMemory();
      assert(false);
   }
   prev_dwDataStart[0] = (pvwdata_t*) calloc(numAxons * nxp * nyp * nfp * nPatches, sizeof(pvwdata_t));
   assert(prev_dwDataStart[0] != NULL);
   for (int arborId = 0; arborId < numAxons; arborId++) {
      prev_dwDataStart[arborId] = (prev_dwDataStart[0] + sp * nPatches * arborId);
      assert(prev_dwDataStart[arborId] != NULL);
   } // loop over arbors

   return PV_SUCCESS;
}

int MomentumConn::ioParamsFillGroup(enum ParamsIOFlag ioFlag) {
   int status = HyPerConn::ioParamsFillGroup(ioFlag);
   ioParam_momentumTau(ioFlag);
   ioParam_momentumMethod(ioFlag);
   ioParam_momentumDecay(ioFlag);
   return status;
}

void MomentumConn::ioParam_momentumTau(enum ParamsIOFlag ioFlag){
   if(plasticityFlag){
      parent->ioParamValue(ioFlag, name, "momentumTau", &momentumTau, momentumTau);
   }
}

/**
 * @brief momentumMethod: The momentum method to use
 * @details Assuming a = dwMax * pre * post
 * simple: deltaW(t) = a + momentumTau * deltaW(t-1)
 * viscosity: deltaW(t) = momentumTau * (deltaW(t-1) + a) * (1-e^(-deltaT/momentumTau))
 * alex: deltaW(t) = momentumTau * delta(t-1) - momentumDecay * dwMax * w(t) - a
 */
void MomentumConn::ioParam_momentumMethod(enum ParamsIOFlag ioFlag){
   if(plasticityFlag){
      parent->ioParamStringRequired(ioFlag, name, "momentumMethod", &momentumMethod);
      if(strcmp(momentumMethod, "simple") != 0 &&
         strcmp(momentumMethod, "viscosity") != 0 &&
         strcmp(momentumMethod, "alex")){
         std::cout << "MomentumConn " << name << ": momentumMethod of " << momentumMethod << " is not known, options are \"simple\", \"viscosity\", and \"alex\"\n";
         exit(-1);
      }
   }
}

void MomentumConn::ioParam_momentumDecay(enum ParamsIOFlag ioFlag){
   if(plasticityFlag){
      parent->ioParamValue(ioFlag, name, "momentumDecay", &momentumDecay, momentumDecay);
      if(momentumDecay < 0 || momentumDecay > 1){
         std::cout << "MomentumConn " << name << ": momentumDecay must be between 0 and 1 inclusive\n";
         exit(-1);
      }
   }
}

//Copied from HyPerConn, only change is a memcpy from dwweights to prev_dwweights
int MomentumConn::updateState(double time, double dt){
   int status = PV_SUCCESS;
   if( !plasticityFlag ) {
      return status;
   }
   update_timer->start();

   if (!combine_dW_with_W_flag) { clear_dW(); }
   for(int arborId=0;arborId<numberOfAxonalArborLists();arborId++) {
      status = calc_dW(arborId);        // Calculate changes in weights
      if (status==PV_BREAK) { break; }
      assert(status == PV_SUCCESS);
   }

   bool needSynchronizing = keepKernelsSynchronized_flag;
   needSynchronizing |= sharedWeights && (parent->simulationTime() >= parent->getStopTime()-parent->getDeltaTime());
   if (needSynchronizing) {
      for (int arborID = 0; arborID < numberOfAxonalArborLists(); arborID++) {
         status = reduceKernels(arborID); // combine partial changes in each column
         if (status == PV_BREAK) {
            break;
         }
         assert(status == PV_SUCCESS);
      }
   }

   //Apply momentum
   for (int arborID = 0; arborID < numberOfAxonalArborLists(); arborID++) {
      status = applyMomentum(arborID);
      if (status == PV_BREAK) {
         break;
      }
      assert(status == PV_SUCCESS);
   }

   //Update prev_dwData buffer
   assert(prev_dwDataStart);
   //After reduce, copy over to prev_dwData
   std::memcpy(*prev_dwDataStart, *get_dwDataStart(),
         sizeof(pvwdata_t) *
         numberOfAxonalArborLists() *
         nxp * nyp * nfp *
         getNumDataPatches());

   for(int arborId=0;arborId<numberOfAxonalArborLists();arborId++){
      status = updateWeights(arborId);  // Apply changes in weights
      if (status==PV_BREAK) { break; }
      assert(status==PV_SUCCESS);
   }
   // normalizeWeights(); // normalizeWeights call moved to HyPerCol::advanceTime loop, to allow for normalization of a group of connections

   update_timer->stop();
   return status;
}

int MomentumConn::applyMomentum(int arbor_ID){
   int nExt = preSynapticLayer()->getNumExtended();
   const PVLayerLoc * loc = preSynapticLayer()->getLayerLoc();
   if(sharedWeights){
      int numKernels = getNumDataPatches();
      //Shared weights done in parallel, parallel in numkernels
#ifdef PV_USE_OPENMP_THREADS
#pragma omp parallel for
#endif
      for(int kernelIdx = 0; kernelIdx < numKernels; kernelIdx++){
         pvwdata_t * dwdata_start  = get_dwDataHead(arbor_ID, kernelIdx);
         pvwdata_t * prev_dw_start = get_prev_dwDataHead(arbor_ID, kernelIdx);
         pvwdata_t * wdata_start   = get_wDataHead(arbor_ID, kernelIdx);
         if(!strcmp(momentumMethod, "simple")){
            for(int k = 0; k < nxp*nyp*nfp; k++){
               dwdata_start[k] += momentumTau * prev_dw_start[k] - momentumDecay*wdata_start[k];
            }
         }
         else if(!strcmp(momentumMethod, "viscosity")){
            for(int k = 0; k < nxp*nyp*nfp; k++){
               dwdata_start[k] = momentumTau * (prev_dw_start[k] + dwdata_start[k]) * (1 - exp(- parent->getDeltaTime() / momentumTau)) - momentumDecay*wdata_start[k];
            }
         }
         else if(!strcmp(momentumMethod, "alex")){
            for(int k = 0; k < nxp*nyp*nfp; k++){
               dwdata_start[k] = momentumTau * prev_dw_start[k] - (1-momentumDecay) * getDWMax()* wdata_start[k] - dwdata_start[k];
            }
         }
      }
   }
   else{
      std::cout << "Momentum not implemented for non-shared weights\n";
      exit(-1);
   }
   return PV_SUCCESS;
}

int MomentumConn::checkpointWrite(const char * cpDir) {
   HyPerConn::checkpointWrite(cpDir);
   if (!plasticityFlag) return PV_SUCCESS;
   char filename[PV_PATH_MAX];
   int chars_needed = snprintf(filename, PV_PATH_MAX, "%s/%s_prev_dW.pvp", cpDir, name);
   if(chars_needed >= PV_PATH_MAX) {
      if ( parent->icCommunicator()->commRank()==0 ) {
         fprintf(stderr, "HyPerConn::checkpointFilename error: path \"%s/%s_W.pvp\" is too long.\n", cpDir, name);
      }
      abort();
   }
   PVPatch *** patches_arg = sharedWeights ? NULL : get_wPatches();
   int status = writeWeights(patches_arg, prev_dwDataStart, getNumDataPatches(), filename, parent->simulationTime(), writeCompressedCheckpoints, /*last*/true);
   assert(status==PV_SUCCESS);
   return PV_SUCCESS;
}

int MomentumConn::checkpointRead(const char * cpDir, double * timeptr) {
   HyPerConn::checkpointRead(cpDir, timeptr);
   if (!plasticityFlag) return PV_SUCCESS;
   clearWeights(prev_dwDataStart, getNumDataPatches(), nxp, nyp, nfp);
   char * path = parent->pathInCheckpoint(cpDir, getName(), "_prev_dW.pvp");
   PVPatch *** patches_arg = sharedWeights ? NULL : get_wPatches();
   double filetime=0.0;
   int status = PV::readWeights(patches_arg, prev_dwDataStart, numberOfAxonalArborLists(), getNumDataPatches(), nxp, nyp, nfp, path, parent->icCommunicator(), &filetime, pre->getLayerLoc());
   if (parent->columnId()==0 && timeptr && *timeptr != filetime) {
      fprintf(stderr, "Warning: \"%s\" checkpoint has timestamp %g instead of the expected value %g.\n", path, filetime, *timeptr);
   }
   free(path);
   return status;
}

} // end namespace PV
<|endoftext|>


<commit_before><commit_msg>Some fixes<commit_after><|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <cmath>
#include "../data/PathSerializer.hpp"
#include "GraphConverter.hpp"

namespace tsp
{

    GraphConverter::GraphConverter()
        : pathFile_(""), dataFile_(""), plotFile_(""), resultFile_("")
    {
    }

    GraphConverter::~GraphConverter()
    {
    }

    int GraphConverter::createPlot(Graph &graph, const std::string &pathFile,
                                   const std::string &resultFile)
    {
        pathFile_ = pathFile;
        dataFile_ = "tsp.dat";
        plotFile_ = "tsp.plt";
        resultFile_ = resultFile;

        // serialize path
        Path path;

        PathSerializer::load(path, pathFile_);

        // write *.dat file
        std::ofstream os(dataFile_);
        os << "#TSP Points\n";
        for(unsigned int i = 0; i < path.size(); ++i) {
            uint nodeId = path[i];
            if(nodeId < graph.size())
                os << graph[nodeId].x() << " " << graph[nodeId].y() << std::endl;
        }
        os.close();

        // write *.plt file
        /*
        set style line <index> {{linetype  | lt} <line_type> | <colorspec>}
                               {{linecolor | lc} <colorspec>}
                               {{linewidth | lw} <line_width>}
                               {{pointtype | pt} <point_type>}
                               {{pointsize | ps} <point_size>}
                               {palette}
        */

        int wHeight = 600, wWidth = 480;
        float density = (float)(wHeight * wWidth) / (path.size() - 1);
        float lineWidth = density / 3000, pointSize = density / 6000;

        os.open(plotFile_, std::ofstream::out);
        os << "set terminal svg size " << wWidth << "," << wHeight <<
           " fname 'Verdana' fsize 10" << std::endl;
        os << "set output '" << resultFile_ << "'" << std::endl;
        os << "set terminal svg enhanced background rgb 'white'" << std::endl;
        os << "set tics font ', 8'" << std::endl;
        os << "set nokey" << std::endl;
        os << "set title 'TSP Graph Visualisation (points: " << path.size() - 1 << ")'"
           << std::endl;
        os << "set style line 1 lc rgb '#0060ad' lt 1 lw " << lineWidth << " pt 7 ps "
           << pointSize << "   # --- blue" << std::endl;
        os << "plot '" << dataFile_ << "' with linespoints ls 1" << std::endl;
        os.close();

        return 0;
    }

    bool GraphConverter::drawGraph()
    {
        const std::string cmd = "gnuplot " + plotFile_;
        system(cmd.c_str());
        //TODO: delete temporary files (tsp.dat and tsp.plt)
        return true;
    }

}
<commit_msg>Change gnuplot commands<commit_after>#include <iostream>
#include <fstream>
#include <cmath>
#include "../data/PathSerializer.hpp"
#include "GraphConverter.hpp"

namespace tsp
{

    GraphConverter::GraphConverter()
        : pathFile_(""), dataFile_(""), plotFile_(""), resultFile_("")
    {
    }

    GraphConverter::~GraphConverter()
    {
    }

    int GraphConverter::createPlot(Graph &graph, const std::string &pathFile,
                                   const std::string &resultFile)
    {
        pathFile_ = pathFile;
        dataFile_ = "tsp.dat";
        plotFile_ = "tsp.plt";
        resultFile_ = resultFile;

        // serialize path
        Path path;

        PathSerializer::load(path, pathFile_);

        // write *.dat file
        std::ofstream os(dataFile_);
        os << "#TSP Points\n";
        for(unsigned int i = 0; i < path.size(); ++i) {
            uint nodeId = path[i];
            if(nodeId < graph.size())
                os << graph[nodeId].x() << " " << graph[nodeId].y() << std::endl;
        }
        os.close();

        // write *.plt file
        /*
        set style line <index> {{linetype  | lt} <line_type> | <colorspec>}
                               {{linecolor | lc} <colorspec>}
                               {{linewidth | lw} <line_width>}
                               {{pointtype | pt} <point_type>}
                               {{pointsize | ps} <point_size>}
                               {palette}
        */

        int wHeight = 600, wWidth = 480;
        float density = (float)(wHeight * wWidth) / (path.size() - 1);
        float lineWidth = density / 3000, pointSize = density / 6000;

        os.open(plotFile_, std::ofstream::out);
        os << "set terminal svg size " << wWidth << "," << wHeight <<
           " fname 'Verdana' fsize 10" << std::endl;
        os << "set output '" << resultFile_ << "'" << std::endl;
        os << "set terminal svg enhanced background rgb 'white'" << std::endl;
        os << "set tics font ', 8'" << std::endl;
        os << "unset key" << std::endl;
        os << "set title 'TSP Graph Visualisation (points: " << path.size() - 1 << ")'"
           << std::endl;
        os << "set style line 1 lc rgb '#0060ad' lt 1 lw " << lineWidth << " pt 7 ps "
           << pointSize << "   # --- blue" << std::endl;
        os << "plot '" << dataFile_ << "' with linespoints ls 1" << std::endl;
	os << "quit" << std::endl;
        os.close();

        return 0;
    }

    bool GraphConverter::drawGraph()
    {
        const std::string cmd = "gnuplot " + plotFile_;
        system(cmd.c_str());
        //TODO: delete temporary files (tsp.dat and tsp.plt)
        return true;
    }

}
<|endoftext|>


<commit_before><commit_msg>C locale toupper/tolower are simple enough to implement that we can bypass STL's slow locale library and provide a faster "dumb" version.<commit_after><|endoftext|>


<commit_before><commit_msg>Improved close behaviour<commit_after><|endoftext|>


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

#include <core/process/Process.hpp>

#include <core/Thread.hpp>

// NOTE: Boost.Process is a proposed boost library for process management
//
// We have an emdedded version of the library which was download on 7/18/2011
// from this location (the file stamps embedded in the archive indicate
// that the code within was last updated on 2/11/2001):
//
//   http://www.highscore.de/boost/gsoc2010/process.zip
//
// Documentation for the library can be found at:
//
//   http://www.highscore.de/boost/gsoc2010/
//
// The following thread includes additional discussion about the
// project and its implementation (this thread was in response to the
// original posting of the code from gsoc2010):
//
//   http://thread.gmane.org/gmane.comp.lib.boost.devel/207594/
//
#include <boost/process/all.hpp>

namespace core {
namespace supervisor {

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

#include <core/process/Process.hpp>

// NOTE: Boost.Process is a proposed boost library for process management
//
// We have an emdedded version of the library which was download on 7/18/2011
// from this location (the file stamps embedded in the archive indicate
// that the code within was last updated on 2/11/2001):
//
//   http://www.highscore.de/boost/gsoc2010/process.zip
//
// Documentation for the library can be found at:
//
//   http://www.highscore.de/boost/gsoc2010/
//
// The following thread includes additional discussion about the
// project and its implementation (this thread was in response to the
// original posting of the code from gsoc2010):
//
//   http://thread.gmane.org/gmane.comp.lib.boost.devel/207594/
//
#include <boost/process/all.hpp>

namespace core {
namespace supervisor {

} // namespace supervisor
} // namespace core
<|endoftext|>