text:
// Copyright 2017-2018 Intel Corporation.

#include "tile/platform/local_machine/scheduler.h"

#include <iterator>
#include <map>
#include <set>
#include <unordered_map>

#include <boost/dynamic_bitset.hpp>

#include "base/util/compat.h"
#include "base/util/error.h"

namespace vertexai {
namespace tile {
namespace local_machine {

namespace {

struct AllocInfo {
  explicit AllocInfo(std::size_t sidx_limit) : accessors(sidx_limit) {}

  boost::dynamic_bitset<> accessors;
  std::string contents;
  bool program_input = false;
  bool read_only = false;
  std::size_t last_writer_sidx = 0;
  std::uint64_t byte_size = 0;
};

// Returns a vector of alloc infos with the names of the temporary variables they contain at the start of a program,
// based
// on the program input allocs.
std::vector<AllocInfo> GetAllocContents(const tile::proto::Program& program, const schedule::Schedule& schedule) {
  std::vector<AllocInfo> alloc_infos{schedule.allocs.size(), AllocInfo{schedule.steps.size()}};
  for (const auto& alloc : schedule.allocs) {
    AllocInfo& ai = alloc_infos[alloc.idx];
    ai.byte_size = alloc.byte_size;
    if (alloc.is_input()) {
      ai.contents = alloc.input;
      ai.program_input = true;
      ai.read_only = !program.inputs().at(alloc.input).consumed();
    }
  }
  return alloc_infos;
}

}  // namespace

schedule::Schedule ToScheduleSteps(const tile::proto::Program& program, const lang::KernelList& kl) {
  schedule::Schedule schedule;

  // Figure out the set of program inputs and outputs that will be
  // accessed directly (i.e. without a copy).  These do not require
  // program-local temporaries.
  std::set<std::string> direct_io;
  for (const auto& input : program.inputs()) {
    direct_io.emplace(input.first);
  }
  for (const auto& output : program.outputs()) {
    direct_io.insert(output.first);
  }

  // Create an alloc for every temporary, and remember the tmp->alloc mappings.
  struct TmpInfo {
    schedule::Alloc* allocp;
    bool needs_output_copy = false;
    std::size_t last_output_kidx = 0;
  };

  std::unordered_map<std::string, TmpInfo> tmps;

  for (const auto& ty : kl.types) {
    if (direct_io.count(ty.first)) {
      continue;
    }
    schedule::Alloc alloc;
    alloc.byte_size = ty.second.byte_size();
    auto ait = schedule.allocs.emplace(schedule.allocs.end(), std::move(alloc));
    tmps[ty.first].allocp = &*ait;
  }

  // Mark the program inputs.
  for (const auto& input : program.inputs()) {
    auto tyit = kl.types.find(input.first);
    if (tyit == kl.types.end()) {
      // An unused input -- unusual, but possible in some cases.
      continue;
    }
    schedule::Alloc alloc;
    alloc.input = input.first;
    alloc.byte_size = tyit->second.byte_size();
    auto ait = schedule.allocs.emplace(schedule.allocs.end(), std::move(alloc));
    tmps[input.first].allocp = &*ait;
  }

  // Mark the program outputs.
  std::set<std::string> program_outputs;
  for (const auto& output_pre_rewrite : program.outputs()) {
    const std::string& output = kl.var_rewrites.Lookup(output_pre_rewrite.first);
    auto tyit = kl.types.find(output);
    if (tyit == kl.types.end()) {
      // An unused output -- unusual, but possible in some cases.
      continue;
    }
    schedule::Alloc alloc;
    alloc.output = output;
    alloc.byte_size = tyit->second.byte_size();
    auto ait = schedule.allocs.emplace(schedule.allocs.end(), std::move(alloc));
    tmps[output].allocp = &*ait;
    program_outputs.insert(output);
  }

  // Since outputs may be generated over multiple kernels, we need to
  // discover the last kernel involved in the construction of any
  // given output.
  for (std::size_t kidx = 0; kidx < kl.kernels.size(); ++kidx) {
    for (const std::string& output : kl.kernels[kidx].outputs) {
      tmps.at(output).last_output_kidx = kidx;
    }
  }

  // Add steps to run the kernels.
  for (std::size_t kidx = 0; kidx < kl.kernels.size(); ++kidx) {
    schedule::Step run{schedule::Step::Tag::kRun};
    run.kidx = kidx;
    const auto& ki = kl.kernels[kidx];

    // Add the inputs before adding the run step, in case we need to
    // copy inputs locally.
    for (const std::string& input : ki.inputs) {
      run.inputs.emplace_back(tmps.at(input).allocp);
    }

    // Add the outputs to the step.
    for (const std::string& output : ki.outputs) {
      schedule::OutputInfo oi{tmps.at(output).allocp, false};
      if (program_outputs.count(output)) {
        oi.add_dep = true;
      }
      auto it = ki.safe_self_aliases.find(output);
      if (it != ki.safe_self_aliases.end()) {
        for (const std::string& safe_self_alias : it->second) {
          const auto& renamed_alias = kl.var_rewrites.Lookup(safe_self_alias);
          oi.allocp->safe_self_alias_allocs.emplace(tmps.at(renamed_alias).allocp);
        }
      }
      run.outputs.emplace_back(oi);
    }

    // Add the step itself to the schedule.
    schedule.steps.emplace(schedule.steps.end(), std::move(run));
  }

  schedule.Reindex();

  return schedule;
}

void AddDataflowDeps(schedule::Schedule* schedule) {
  std::map<schedule::Alloc*, schedule::Step*> latest_tmp_writer;
  for (auto& step : schedule->steps) {
    step.deps.clear();
    IVLOG(5, "Adding dataflow deps to s" << step.idx);
    for (schedule::Alloc* allocp : step.inputs) {
      if (!allocp->byte_size) {
        return;
      }
      auto ltwit = latest_tmp_writer.find(allocp);
      if (ltwit == latest_tmp_writer.end()) {
        if (!allocp->is_input()) {
          std::stringstream ss;
          ss << "Program fails to initialize non-empty temporary for a" << allocp->idx;
          throw error::Internal(ss.str());
        }
      } else {
        IVLOG(5, "  Adding dep on a" << allocp->idx << " with last writer s" << ltwit->second->idx);
        step.deps.insert(ltwit->second);
      }
    }
    for (schedule::OutputInfo oi : step.outputs) {
      schedule::Alloc* allocp = oi.allocp;
      IVLOG(5, "  Adding output dep on a" << allocp->idx);
      auto res = latest_tmp_writer.emplace(allocp, &step);
      if (res.second) {
        IVLOG(5, "    This was the first writer");
        // This was the first insertion of this alloc; everything is good.
        continue;
      }

      IVLOG(5, "    Alloc had been written by s" << res.first->second->idx);

      // The alloc already existed in the map -- so some other step
      // already updated part of the alloc.  The current step has a
      // dependency on that previous writer.
      step.deps.insert(res.first->second);

      // The current step becomes the latest writer.
      res.first->second = &step;
    }
  }
}

void AddLinearDeps(schedule::Schedule* schedule, std::size_t delta) {
  if (schedule->steps.size() <= delta) {
    return;
  }
  auto dep = schedule->steps.begin();
  auto it = dep;
  std::advance(it, delta);
  while (it != schedule->steps.end()) {
    it->deps.insert(&*dep);
    ++dep;
    ++it;
  }
}

void ValidateSchedule(const tile::proto::Program& program, const lang::KernelList& kl,
                      const schedule::Schedule& schedule) {
  boost::dynamic_bitset<> scheduled_kidxs{kl.kernels.size()};
  std::vector<boost::dynamic_bitset<>> transitive_deps{schedule.steps.size(),
                                                       boost::dynamic_bitset<>(schedule.steps.size())};
  std::vector<AllocInfo> alloc_infos = GetAllocContents(program, schedule);

  std::size_t sidx = 0;
  for (const auto& step : schedule.steps) {
    for (const auto& dep : step.deps) {
      if (sidx <= dep->idx) {
        throw error::Internal{"Schedule deps are not ordered at s" + std::to_string(sidx)};
      }
      std::size_t dep_sidx = dep->idx;
      transitive_deps[sidx].set(dep_sidx);
      transitive_deps[sidx] |= transitive_deps[dep_sidx];
    }

    std::vector<std::string> new_contents;

    switch (step.tag) {
      case schedule::Step::Tag::kRun: {
        // Verify scheduling.
        if (scheduled_kidxs.size() <= step.kidx) {
          throw error::Internal{"Schedule contains an invalid kernel index at s" + std::to_string(sidx)};
        }
        if (scheduled_kidxs.test(step.kidx)) {
          throw error::Internal{"Schedule runs a kernel multiple times at s" + std::to_string(sidx)};
        }
        scheduled_kidxs.set(step.kidx);
        const auto& ki = kl.kernels[step.kidx];
        // Verify that all inputs are valid.
        if (ki.inputs.size() != step.inputs.size()) {
          throw error::Internal{"Schedule specifies an incorrect number of kernel inputs at s" + std::to_string(sidx)};
        }
        for (std::size_t iidx = 0; iidx < ki.inputs.size(); ++iidx) {
          std::size_t aidx = step.inputs[iidx]->idx;
          if (alloc_infos[aidx].contents != ki.inputs[iidx]) {
            throw error::Internal{"Schedule specifies an incorrect tensor read at s" + std::to_string(sidx)};
          }
        }
        // Verify that all outputs are valid.
        if (ki.outputs.size() != step.outputs.size()) {
          throw error::Internal{"Schedule specifies an incorrect number of kernel outputs at s" + std::to_string(sidx)};
        }
        new_contents = ki.outputs;
        break;
      }
      case schedule::Step::Tag::kCopy: {
        if (step.outputs.size() != 1) {
          throw error::Internal{
              "In schedule validation: copy step " + std::to_string(sidx) +
              " has an incorrect output count; expected: 1, got: " + std::to_string(step.outputs.size())};
        }
        if (step.inputs.size() != 1) {
          throw error::Internal{
              "In schedule validation: copy step " + std::to_string(sidx) +
              " has an incorrect input count; expected: 1, got: " + std::to_string(step.inputs.size())};
        }
        const std::string& contents = alloc_infos[step.inputs[0]->idx].contents;
        std::uint64_t tensor_size = kl.types.at(contents).byte_size();
        if (tensor_size != step.byte_count) {
          throw error::Internal{"Schedule copy size mismatch at s" + std::to_string(sidx) + " (copying " +
                                std::to_string(step.byte_count) + " bytes; tensor \"" + contents + "\" contains " +
                                std::to_string(tensor_size) + " bytes)"};
        }
        new_contents.emplace_back(contents);
        break;
      }
      default:
        throw error::Internal{"In validation: step " + std::to_string(sidx) + " has an invalid tag"};
    }

    for (auto* allocp : step.inputs) {
      std::size_t aidx = allocp->idx;
      if (alloc_infos.size() <= aidx) {
        throw error::Internal{"Schedule specifies an undefined input alloc at s" + std::to_string(sidx)};
      }
      auto& ainfo = alloc_infos[aidx];
      if (!ainfo.contents.length()) {
        throw error::Internal{"Schedule reads an uninitialized tensor at s" + std::to_string(sidx)};
      }
      if (!ainfo.program_input && !transitive_deps[sidx].test(ainfo.last_writer_sidx)) {
        throw error::Internal{"Schedule reads tensor a" + std::to_string(aidx) + " \"" + ainfo.contents + "\" at s" +
                              std::to_string(sidx) + " prior to its write"};
      }
      ainfo.accessors.set(sidx);
    }

    for (std::size_t oidx = 0; oidx < new_contents.size(); ++oidx) {
      auto* allocp = step.outputs[oidx].allocp;

      std::size_t aidx = allocp->idx;
      if (alloc_infos.size() <= aidx) {
        throw error::Internal{"Schedule specifies an undefined output alloc at s" + std::to_string(sidx)};
      }
      auto& ainfo = alloc_infos[aidx];
      if (ainfo.read_only) {
        LOG(ERROR) << "Schedule specified a write to a read-only tensor: " << step;
        LOG(ERROR) << schedule;
        throw error::Internal{"Schedule specifies a write to a read-only tensor at s" + std::to_string(sidx)};
      }
      // All current accessors should be in the current step's transitive dependency set.
      // Note that we add the current step as a self-dependency in this check, to account for steps
      // that reuse allocs for different temporaries.  TODO: Only add the self-dep for cases where codegen
      // says it's okay to reuse an input alloc for an output.
      auto deps = transitive_deps[sidx];
      deps.set(sidx);
      if (((deps & ainfo.accessors) ^ ainfo.accessors).any()) {
        throw error::Internal{"Schedule writes a tensor to a live alloc at s" + std::to_string(sidx)};
      }
      std::uint64_t tensor_size = kl.types.at(new_contents[oidx]).byte_size();
      if (ainfo.byte_size < tensor_size) {
        throw error::Internal{"Schedule writes tensor \"" + new_contents[oidx] + "\" of " +
                              std::to_string(tensor_size) + " bytes to alloc a" + std::to_string(aidx) + " of " +
                              std::to_string(ainfo.byte_size) + " bytes at s" + std::to_string(sidx)};
      }

      // The current step becomes the last writer and the only current
      // accessor.
      ainfo.last_writer_sidx = sidx;
      ainfo.accessors.reset();
      ainfo.accessors.set(sidx);
      ainfo.contents = new_contents[oidx];
    }

    sidx++;
  }

  if (!scheduled_kidxs.all()) {
    throw error::Internal{"Schedule does not run all kernels"};
  }

  std::unordered_map<std::string, bool> outputs;
  for (const auto& output : program.outputs()) {
    outputs[kl.var_rewrites.Lookup(output.first)] = false;
  }

  for (const auto& alloc : schedule.allocs) {
    if (!alloc.is_output()) {
      continue;
    }
    const std::string& contents = alloc_infos[alloc.idx].contents;
    if (alloc.output != contents) {
      throw error::Internal{"Schedule ends with tensor \"" + contents + " in program output \"" + alloc.output + "\""};
    }
    if (alloc.byte_size != alloc_infos[alloc.idx].byte_size) {
      throw error::Internal{"Schedule writes output " + alloc.output + " [size=" + std::to_string(alloc.byte_size) +
                            " to an alloc size=" + std::to_string(alloc_infos[alloc.idx].byte_size)};
    }
    auto it = outputs.find(alloc.output);
    if (it == outputs.end()) {
      throw error::Internal{"Schedule writes output \"" + alloc.output + "\", which is not defined in the program"};
    }
    if (it->second) {
      throw error::Internal{"Schedule defines program output \"" + alloc.output + "\" multiple times"};
    }
    it->second = true;
  }
  for (auto& kvp : outputs) {
    if (!kvp.second && kl.types.count(kvp.first)) {
      throw error::Internal{"Schedule fails to write program output \"" + kvp.first + "\""};
    }
  }
}

inline std::size_t AlignUp(std::size_t byte_size, std::size_t alignment) {
  return ((byte_size + alignment - 1) / alignment) * alignment;
}

std::size_t TotalAllocSize(const schedule::Schedule& schedule, std::size_t alignment) {
  std::size_t total_size = 0;
  for (const auto& alloc : schedule.allocs) {
    total_size += AlignUp(alloc.byte_size, alignment);
  }
  return total_size;
}

void SummarizeSchedule(hal::proto::CompilationInfo* cinfo, const tile::proto::Program& program,
                       const lang::KernelList& kl, const schedule::Schedule& schedule) {
  IVLOG(1, "Summary for " << program.id() << ":");

  IVLOG(3, "Schedule:\n" << schedule);

  std::map<std::size_t, std::size_t> tmp_size_counts;
  std::size_t tmp_count = 0;

  for (const auto& kvp : kl.types) {
    if (program.inputs().count(kvp.first) || program.outputs().count(kvp.first)) {
      continue;
    }
    tmp_count++;
    const auto& shape = kvp.second;
    auto res = tmp_size_counts.emplace(shape.byte_size(), 1);
    if (!res.second) {
      res.first->second += 1;
    }
  }

  std::size_t alloc_count = 0;
  std::uint64_t total_bytes = 0;
  std::map<std::size_t, std::size_t> size_counts;

  for (const auto& alloc : schedule.allocs) {
    alloc_count++;
    total_bytes += alloc.byte_size;
    auto res = size_counts.emplace(alloc.byte_size, 1);
    if (!res.second) {
      res.first->second += 1;
    }
  }

  IVLOG(2, "Tmp count: " << tmp_count);
  IVLOG(2, "Tmp sizes: ");
  for (auto it : tmp_size_counts) {
    IVLOG(2, "  " << it.first << ": " << it.second);
    if (cinfo) {
      (*cinfo->mutable_tmp_sizes())[it.first] = it.second;
    }
  }
  IVLOG(1, "Alloc count: " << alloc_count);
  IVLOG(1, "Alloc sizes: ");
  for (auto it : size_counts) {
    IVLOG(1, "  " << it.first << ": " << it.second);
    if (cinfo) {
      (*cinfo->mutable_alloc_sizes())[it.first] = it.second;
    }
  }
  IVLOG(1, "Total memory required: " << total_bytes << " bytes");
}

}  // namespace local_machine
}  // namespace tile
}  // namespace vertexai

ext: cc

max_stars_repo_name: redoclag/plaidml

max_issues_repo_name: HOZHENWAI/plaidml

max_forks_repo_name: HOZHENWAI/plaidml


text: #include <boost/numeric/odeint/external/mpi/mpi_vector_state.hpp>

ext: hpp

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
#include "ScalePyramid.hpp"
#include <Danvil/Tools/MoreMath.h>
#include <boost/assert.hpp>
#include <iostream>
//----------------------------------------------------------------------------//
namespace density {
//----------------------------------------------------------------------------//

Eigen::MatrixXf SumMipMapWithBlackBorder(const Eigen::MatrixXf& img_big)
{
	size_t w_big = img_big.rows();
	size_t h_big = img_big.cols();
	// the computed mipmap will have 2^i size
	unsigned int size = Danvil::MoreMath::P2Ceil(std::max(w_big, h_big));
	Eigen::MatrixXf img_small(size / 2, size / 2);
	img_small.fill({0.0f});
	// only the part where at least one of the four pixels lies in the big image is iterated
	// the rest was set to 0 with the fill op
	size_t w_small = w_big / 2 + ((w_big % 2 == 0) ? 0 : 1);
	size_t h_small = h_big / 2 + ((h_big % 2 == 0) ? 0 : 1);
	for(size_t y = 0; y < h_small; y++) {
		size_t y_big = y * 2;
		for(size_t x = 0; x < w_small; x++) {
			size_t x_big = x * 2;
			// We sum over all four pixels in the big image (if they are valid).
			// May by invalid because the big image is considered to be enlarged
			// to have a size of 2^i.
			float sum = 0.0f;
			// Since we only test the part where at least one pixel is in also in the big image
			// we do not need to test that (x_big,y_big) is a valid pixel in the big image.
			const float* p_big = &img_big(x_big, y_big);
			sum += *(p_big);
			if(x_big + 1 < w_big) {
				sum += *(p_big + 1);
			}
			if(y_big + 1 < h_big) {
				sum += *(p_big + w_big);
				if(x_big + 1 < w_big) {
					sum += *(p_big + w_big + 1);
				}
			}
			img_small(x, y) = sum;
		}
	}
	return img_small;
}

Eigen::MatrixXf ScaleUp(const Eigen::MatrixXf& img_small, const unsigned int S)
{
	if(S == 0) {
		return Eigen::MatrixXf::Zero(0,0);
	}
	if(S == 1) {
		return img_small;
	}
	// size of original image
	const unsigned int w_sma = img_small.rows();
	const unsigned int h_sma = img_small.cols();
	// size of scaled up image
	const unsigned int w_big = w_sma * S;
	const unsigned int h_big = h_sma * S;
	Eigen::MatrixXf img_big(w_big, h_big);
	for(unsigned int y=0; y<h_sma; ++y) {
		const unsigned int y_big = S*y;
		for(unsigned int x=0; x<w_sma; ++x) {
			const unsigned int x_big = S*x;
			const float val = img_small(x, y);
			for(unsigned int i=0; i<S; ++i) {
				for(unsigned int j=0; j<S; ++j) {
					img_big(x_big+j, y_big+i) = val;
				}
			}
		}
	}
	return img_big;
}

std::vector<Eigen::MatrixXf> ComputeMipmaps(const Eigen::MatrixXf& img, unsigned int min_size)
{
	// find number of required mipmap level
	unsigned int max_size = std::max(img.rows(), img.cols());
	int n_mipmaps = Danvil::MoreMath::PowerOfTwoExponent(max_size);
	n_mipmaps -= Danvil::MoreMath::PowerOfTwoExponent(min_size);
	BOOST_ASSERT(n_mipmaps >= 1);
	std::vector<Eigen::MatrixXf> mipmaps(n_mipmaps);
	mipmaps[0] = SumMipMapWithBlackBorder(img);
	// create remaining mipmaps
	for(unsigned int i=1; i<n_mipmaps; i++) {
		BOOST_ASSERT(mipmaps[i-1].rows() == mipmaps[i-1].cols());
		BOOST_ASSERT(mipmaps[i-1].rows() >= 1);
		mipmaps[i] = SumMipMap<2>(mipmaps[i - 1]);
//		std::cout << std::accumulate(mipmaps[i].begin(), mipmaps[i].end(), 0.0f, [](float sum, float x) { return sum + x; }) << std::endl;
	}
	return mipmaps;
}

std::vector<Eigen::MatrixXf> ComputeMipmapsLevels(const Eigen::MatrixXf& img, unsigned int n_mipmaps)
{
	// find number of required mipmap level
	unsigned int max_size = std::max(img.rows(), img.cols());
	BOOST_ASSERT(n_mipmaps >= 1);
	std::vector<Eigen::MatrixXf> mipmaps(n_mipmaps);
	mipmaps[0] = SumMipMapWithBlackBorder(img);
	// create remaining mipmaps
	for(unsigned int i=1; i<n_mipmaps; i++) {
		BOOST_ASSERT(mipmaps[i-1].rows() == mipmaps[i-1].cols());
		BOOST_ASSERT(mipmaps[i-1].rows() >= 1);
		mipmaps[i] = SumMipMap<2>(mipmaps[i - 1]);
//		std::cout << std::accumulate(mipmaps[i].begin(), mipmaps[i].end(), 0.0f, [](float sum, float x) { return sum + x; }) << std::endl;
	}
	return mipmaps;
}

std::vector<Eigen::MatrixXf> ComputeMipmaps640x480(const Eigen::MatrixXf& img)
{
	// 640 = 4*32*5
	// 480 = 3*32*5
	// 32 = 2^5
	if(img.rows() != 640 || img.cols() != 480) {
		throw std::runtime_error("ERROR: ComputeMipmaps640x480 required size 640x480!");
	}
	std::vector<Eigen::MatrixXf> v(6);
	v[0] = SumMipMap<5>(img);
	for(unsigned int i=0; i<5; i++) {
		v[i+1] = SumMipMap<2>(v[i]);
	}
	return v;
}

std::vector<std::pair<Eigen::MatrixXf,Eigen::MatrixXf>> ComputeMipmapsWithAbs(const Eigen::MatrixXf& img, unsigned int min_size)
{
	// find number of required mipmap level
	unsigned int max_size = std::max(img.rows(), img.cols());
	int n_mipmaps = Danvil::MoreMath::PowerOfTwoExponent(max_size);
	n_mipmaps -= Danvil::MoreMath::PowerOfTwoExponent(min_size);
	BOOST_ASSERT(n_mipmaps >= 1);
	std::vector<std::pair<Eigen::MatrixXf,Eigen::MatrixXf>> mipmaps(n_mipmaps + 1);
	mipmaps[0].first = img;
	mipmaps[0].second = img.cwiseAbs();
	mipmaps[1].first = SumMipMapWithBlackBorder(mipmaps[0].first);
	mipmaps[1].second = SumMipMapWithBlackBorder(mipmaps[0].second);
	for(unsigned int i=2; i<=n_mipmaps; i++) {
		//BOOST_ASSERT(mipmaps[i-1].width() == mipmaps[i-1].height());
		//BOOST_ASSERT(mipmaps[i-1].width() >= 1);
		mipmaps[i].first = SumMipMap<2>(mipmaps[i - 1].first);
		mipmaps[i].second = SumMipMap<2>(mipmaps[i - 1].second);
	}
	return mipmaps;
}

//----------------------------------------------------------------------------//
}
//----------------------------------------------------------------------------//

ext: cpp

max_stars_repo_name: jbellis/superpixel-benchmark

max_issues_repo_name: jbellis/superpixel-benchmark

max_forks_repo_name: jbellis/superpixel-benchmark


text:
#pragma once

#include <Eigen/Dense>

#include "Point.hpp"

namespace Geometry2d {
// A 2x3 transformation matrix.
//
// This is the 2D equivalent of the usual 3D tranformation matrix with the
// bottom row omitted because the bottom (third) element of a 2D point is always
// 1.  The third row of the matrix is understood to be [0 0 1].
class TransformMatrix {
public:
    TransformMatrix() {
        _m[0] = 1;
        _m[1] = 0;
        _m[2] = 0;
        _m[3] = 0;
        _m[4] = 1;
        _m[5] = 0;
    }

    TransformMatrix(float a, float b, float c, float d, float e, float f) {
        _m[0] = a;
        _m[1] = b;
        _m[2] = c;
        _m[3] = d;
        _m[4] = e;
        _m[5] = f;
    }

    TransformMatrix(Geometry2d::Point origin, float rotation = 0,
                    bool mirror = false, float scale = 1);

    TransformMatrix(const Eigen::Matrix<double, 3, 3>& other) {
        _m[0] = other(0, 0);
        _m[1] = other(0, 1);
        _m[2] = other(0, 2);
        _m[3] = other(1, 0);
        _m[4] = other(1, 1);
        _m[5] = other(1, 2);
    }

    TransformMatrix operator*(const TransformMatrix& other) const {
        float a = _m[0] * other._m[0] + _m[1] * other._m[3];
        float b = _m[0] * other._m[1] + _m[1] * other._m[4];
        float c = _m[0] * other._m[2] + _m[1] * other._m[5] + _m[2];
        float d = _m[3] * other._m[0] + _m[4] * other._m[3];
        float e = _m[3] * other._m[1] + _m[4] * other._m[4];
        float f = _m[3] * other._m[2] + _m[4] * other._m[5] + _m[5];

        return TransformMatrix(a, b, c, d, e, f);
    }

    TransformMatrix& operator*=(const TransformMatrix& other) {
        float a = _m[0] * other._m[0] + _m[1] * other._m[3];
        float b = _m[0] * other._m[1] + _m[1] * other._m[4];
        float c = _m[0] * other._m[2] + _m[1] * other._m[5] + _m[2];
        float d = _m[3] * other._m[0] + _m[4] * other._m[3];
        float e = _m[3] * other._m[1] + _m[4] * other._m[4];
        float f = _m[3] * other._m[2] + _m[4] * other._m[5] + _m[5];

        _m[0] = a;
        _m[1] = b;
        _m[2] = c;
        _m[3] = d;
        _m[4] = e;
        _m[5] = f;

        return *this;
    }

    operator Eigen::Matrix<double, 3, 3>() const {
        Eigen::Matrix<double, 3, 3> result;
        result << _m[0], _m[1], _m[2], _m[3], _m[4], _m[5], 0, 0, 1;
        return result;
    }

    Point operator*(const Point& pt) const {
        return Point(pt.x() * _m[0] + pt.y() * _m[1] + _m[2],
                     pt.x() * _m[3] + pt.y() * _m[4] + _m[5]);
    }

    // Transforms a direction vector (3rd element is zero)
    Point transformDirection(const Point& dir) const {
        return Point(dir.x() * _m[0] + dir.y() * _m[1],
                     dir.x() * _m[3] + dir.y() * _m[4]);
    }

    // Transforms the given angle in radians
    float transformAngle(float angle) const;

    // Returns the vector that represents the direction of the transformed
    // X-axis.
    Point x() const { return Point(_m[0], _m[3]); }

    // Returns the vector that represents the direction of the transformed
    // Y-axis.
    Point y() const { return Point(_m[1], _m[4]); }

    // Returns the origin of the transformed coordinate system
    Point origin() const { return Point(_m[2], _m[5]); }

    // Returns the scaling along the transformed X-axis.
    float xScale() const { return x().mag(); }

    // Returns the scaling along the transformed Y-axis.
    float yScale() const { return y().mag(); }

    // Returns the clockwise angle from the transformed Y axis to the original Y
    // axis. This is not affected by horizontal reflection.
    float rotation() const;

    // Returns true if the coordinate system has been mirrored (i.e. is now
    // left-handed).
    bool mirrored() const;

    const float* m() const { return _m; }

    ////////////////
    // Functions to build common transformations:

    // Translation
    static TransformMatrix translate(const Point& delta) {
        return TransformMatrix(1, 0, delta.x(), 0, 1, delta.y());
    }

    static TransformMatrix translate(float x, float y) {
        return translate(Point(x, y));
    }

    // Rotation in radians around origin
    static TransformMatrix rotate(float angle) {
        float c = cos(angle);
        float s = sin(angle);

        return TransformMatrix(c, -s, 0, s, c, 0);
    }

    // Uniform scale
    static TransformMatrix scale(float s) {
        return TransformMatrix(s, 0, 0, 0, s, 0);
    }

    // Non-uniform scale
    static TransformMatrix scale(float x, float y) {
        return TransformMatrix(x, 0, 0, 0, y, 0);
    }

    // Returns a matrix to rotate <angle> radians CCW around <center>.
    static TransformMatrix rotateAroundPoint(const Point& center, float angle);

    // Returns a matrix to reflect along the line parallel to the Y-axis
    // containing <center>.
    static TransformMatrix mirrorAroundPoint(const Point& center);

    static const TransformMatrix identity;
    static const TransformMatrix mirrorX;

protected:
    // Matrix values in row-major order.
    //
    // Indices:
    //   [0 1 2
    //    3 4 5]
    float _m[6];
};
}  // namespace Geometry2d


text:
/*
 * Copyright (c) 2015-2021 Agalmic Ventures LLC (www.agalmicventures.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "CommandManager.hpp"

#include <boost/algorithm/string.hpp>

#include "Command.hpp"

namespace werk
{

bool CommandManager::execute(const std::string &commandLine)
{
	//History is only added here, from human executions. This enables neat stuff like the redo
	//command and allows the command system to still be used in an automated fashion.
	_commandHistory.emplace_back(_clock.time(), commandLine);
	_log->log(LogLevel::JSON, "{\"type\":\"command.received\",\"commandLine\":\"%s\"}", commandLine.c_str());

	//Parse the arguments, ignoring extra whitespace
	std::string trimmedCommandLine = boost::trim_copy(commandLine);
	std::vector<std::string> arguments;
	boost::split(arguments, trimmedCommandLine, boost::is_any_of(" \t"), boost::token_compress_on);
	return arguments[0] == "" ? false : execute(arguments);
}

bool CommandManager::execute(const std::vector<std::string> &arguments)
{
	if (arguments.empty()) {
		_log->logRaw(LogLevel::CRITICAL, "Got zero-length arguments to CommandManager::execute");
		return false;
	}

	const std::string &commandName = arguments[0];
	auto commandIter = _commands.find(commandName);
	if (commandIter == _commands.end()) {
		_log->log(LogLevel::ERROR, "Command not found: %s", commandName.c_str());
		return false;
	}

	Command *command = commandIter->second;
	return command->execute(arguments);
}

CommandAction *CommandManager::newCommandAction(const std::string &name, const std::string &commandLine)
{
	std::vector<std::string> arguments;
	boost::split(arguments, commandLine, boost::is_any_of(" \t"));
	const std::string &commandName = arguments[0];
	auto commandIter = _commands.find(commandName);
	if (commandIter == _commands.end()) {
		_log->log(LogLevel::ERROR, "Command not found for action: %s", commandName.c_str());
		return nullptr;
	}

	Command *command = commandIter->second;
	CommandAction *commandAction = new CommandAction(name, command);
	commandAction->arguments() = arguments;
	return commandAction;
}

void CommandManager::logTo(Log *log) const
{
	log->log(LogLevel::INFO, "<CommandManager> Commands (%zu):", _commands.size());
	for (const auto &i : _commands) {
		_log->log(LogLevel::INFO, "  %16s   %s", i.first.c_str(), i.second->help().c_str());
	}
}

}

max_stars_repo_name: AgalmicVentures/Werk

max_issues_repo_name: AgalmicVentures/Werk

max_forks_repo_name: AgalmicVentures/Werk


text:
// Boost.Range library
//
//  Copyright Neil Groves 2009. Use, modification and
//  distribution is subject to the Boost Software License, Version
//  1.0. (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//
// Acknowledgements:
// aschoedl supplied a fix to supply the level of interoperability I had
// originally intended, but failed to implement.
//
// For more information, see http://www.boost.org/libs/range/
//
#ifndef BOOST_RANGE_DETAIL_DEMOTE_ITERATOR_TRAVERSAL_TAG_HPP_INCLUDED
#define BOOST_RANGE_DETAIL_DEMOTE_ITERATOR_TRAVERSAL_TAG_HPP_INCLUDED

#include <boost/iterator/iterator_categories.hpp>

namespace mars_boost {}
namespace boost = mars_boost;
namespace mars_boost {
namespace range_detail {

template<class IteratorTraversalTag1, class IteratorTraversalTag2>
struct inner_demote_iterator_traversal_tag {
};

#define BOOST_DEMOTE_TRAVERSAL_TAG(Tag1, Tag2, ResultTag) \
template<> struct inner_demote_iterator_traversal_tag< Tag1 , Tag2 > \
{ \
    typedef ResultTag type; \
};

BOOST_DEMOTE_TRAVERSAL_TAG(no_traversal_tag, no_traversal_tag, no_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(no_traversal_tag, incrementable_traversal_tag, no_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(no_traversal_tag, single_pass_traversal_tag, no_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(no_traversal_tag, forward_traversal_tag, no_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(no_traversal_tag, bidirectional_traversal_tag, no_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(no_traversal_tag, random_access_traversal_tag, no_traversal_tag)

BOOST_DEMOTE_TRAVERSAL_TAG(incrementable_traversal_tag, no_traversal_tag, no_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(incrementable_traversal_tag, incrementable_traversal_tag, incrementable_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(incrementable_traversal_tag, single_pass_traversal_tag, incrementable_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(incrementable_traversal_tag, forward_traversal_tag, incrementable_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(incrementable_traversal_tag, bidirectional_traversal_tag, incrementable_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(incrementable_traversal_tag, random_access_traversal_tag, incrementable_traversal_tag)

BOOST_DEMOTE_TRAVERSAL_TAG(single_pass_traversal_tag, no_traversal_tag, no_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(single_pass_traversal_tag, incrementable_traversal_tag, incrementable_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(single_pass_traversal_tag, single_pass_traversal_tag, single_pass_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(single_pass_traversal_tag, forward_traversal_tag, single_pass_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(single_pass_traversal_tag, bidirectional_traversal_tag, single_pass_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(single_pass_traversal_tag, random_access_traversal_tag, single_pass_traversal_tag)

BOOST_DEMOTE_TRAVERSAL_TAG(forward_traversal_tag, no_traversal_tag, no_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(forward_traversal_tag, incrementable_traversal_tag, incrementable_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(forward_traversal_tag, single_pass_traversal_tag, single_pass_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(forward_traversal_tag, forward_traversal_tag, forward_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(forward_traversal_tag, bidirectional_traversal_tag, forward_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(forward_traversal_tag, random_access_traversal_tag, forward_traversal_tag)

BOOST_DEMOTE_TRAVERSAL_TAG(bidirectional_traversal_tag, no_traversal_tag, no_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(bidirectional_traversal_tag, incrementable_traversal_tag, incrementable_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(bidirectional_traversal_tag, single_pass_traversal_tag, single_pass_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(bidirectional_traversal_tag, forward_traversal_tag, forward_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(bidirectional_traversal_tag, bidirectional_traversal_tag, bidirectional_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(bidirectional_traversal_tag, random_access_traversal_tag, bidirectional_traversal_tag)

BOOST_DEMOTE_TRAVERSAL_TAG(random_access_traversal_tag, no_traversal_tag, no_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(random_access_traversal_tag, incrementable_traversal_tag, incrementable_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(random_access_traversal_tag, single_pass_traversal_tag, single_pass_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(random_access_traversal_tag, forward_traversal_tag, forward_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(random_access_traversal_tag, bidirectional_traversal_tag, bidirectional_traversal_tag)
BOOST_DEMOTE_TRAVERSAL_TAG(random_access_traversal_tag, random_access_traversal_tag, random_access_traversal_tag)

#undef BOOST_DEMOTE_TRAVERSAL_TAG

template<class IteratorTraversalTag1, class IteratorTraversalTag2>
struct demote_iterator_traversal_tag
    : inner_demote_iterator_traversal_tag<
        typename mars_boost::iterators::pure_traversal_tag<IteratorTraversalTag1>::type,
        typename mars_boost::iterators::pure_traversal_tag<IteratorTraversalTag2>::type
    > {
};

} // namespace range_detail
} // namespace mars_boost {} namespace boost = mars_boost; namespace mars_boost

#endif // include guard

max_stars_repo_name: habbyge/mars

max_issues_repo_name: habbyge/mars

max_forks_repo_name: habbyge/mars


text:
#ifndef BOOST_NETWORK_PROTOCOL_HTTP_POLICIES_ASYNC_RESOLVER_20100622
#define BOOST_NETWORK_PROTOCOL_HTTP_POLICIES_ASYNC_RESOLVER_20100622

// Copyright Dean Michael Berris 2010.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#include <boost/enable_shared_from_this.hpp>
#include <boost/asio/placeholders.hpp>
#include <boost/asio/strand.hpp>

namespace boost {
namespace network {
namespace http {
namespace policies {

template <class Tag>
struct async_resolver : boost::enable_shared_from_this<async_resolver<Tag> > {
  typedef typename resolver<Tag>::type resolver_type;
  typedef typename resolver_type::iterator resolver_iterator;
  typedef typename resolver_type::query resolver_query;
  typedef std::pair<resolver_iterator, resolver_iterator>
      resolver_iterator_pair;
  typedef typename string<Tag>::type string_type;
  typedef boost::unordered_map<string_type, resolver_iterator_pair>
      endpoint_cache;
  typedef boost::function<
      void(boost::system::error_code const &, resolver_iterator_pair)>
      resolve_completion_function;
  typedef boost::function<void(resolver_type &, string_type, boost::uint16_t,
                               resolve_completion_function)> resolve_function;

 protected:
  bool cache_resolved_;
  endpoint_cache endpoint_cache_;
  boost::shared_ptr<boost::asio::io_service> service_;
  boost::shared_ptr<boost::asio::io_service::strand> resolver_strand_;

  explicit async_resolver(bool cache_resolved)
      : cache_resolved_(cache_resolved), endpoint_cache_() {}

  void resolve(resolver_type &resolver_, string_type const &host,
               boost::uint16_t port,
               resolve_completion_function once_resolved) {
    if (cache_resolved_) {
      typename endpoint_cache::iterator iter =
          endpoint_cache_.find(boost::to_lower_copy(host));
      if (iter != endpoint_cache_.end()) {
        boost::system::error_code ignored;
        once_resolved(ignored, iter->second);
        return;
      }
    }

    typename resolver_type::query q(host,
                                    lexical_cast<string_type>(port));
    resolver_.async_resolve(q, resolver_strand_->wrap(boost::bind(
                                   &async_resolver<Tag>::handle_resolve,
                                   async_resolver<Tag>::shared_from_this(),
                                   boost::to_lower_copy(host), once_resolved,
                                   boost::asio::placeholders::error,
                                   boost::asio::placeholders::iterator)));
  }

  void handle_resolve(string_type const &host,
                      resolve_completion_function once_resolved,
                      boost::system::error_code const &ec,
                      resolver_iterator endpoint_iterator) {
    typename endpoint_cache::iterator iter;
    bool inserted = false;
    if (!ec && cache_resolved_) {
      boost::fusion::tie(iter, inserted) =
          endpoint_cache_.insert(std::make_pair(
              host, std::make_pair(endpoint_iterator, resolver_iterator())));
      once_resolved(ec, iter->second);
    } else {
      once_resolved(ec, std::make_pair(endpoint_iterator, resolver_iterator()));
    }
  }
};

}  // namespace policies

}  // namespace http

}  // namespace network

}  // namespace boost

#endif  // BOOST_NETWORK_PROTOCOL_HTTP_POLICIES_ASYNC_RESOLVER_20100622

max_stars_repo_name: ChadSki/Phasor


text:
/*
 ******************************************************************************
 Project:      OWA SWMM
 Version:      5.1.13
 Module:       test_errormanager.cpp
 Description:  tests for error manager
 Authors:      see AUTHORS
 Copyright:    see AUTHORS
 License:      see LICENSE
 Last Updated: 12/21/2020
 ******************************************************************************
 */

#define BOOST_TEST_MODULE errormanager

#include <boost/test/unit_test.hpp>

#include "shared/errormanager.h"

#define MESSAGE_STRING "This is unit testing!"

void mock_lookup(int errcode, char *errmsg, int len)
{
    char *msg = NULL;

    if (errcode == 100) {
        msg = (char *)MESSAGE_STRING;
    }
    else {
        msg = (char *)"";
    }
    strncpy(errmsg, msg, len);
}

boost::test_tools::predicate_result check_string(std::string test, std::string ref)
{
    if (ref.compare(test) == 0)
        return true;
    else
        return false;
}

BOOST_AUTO_TEST_SUITE(test_errormanager)

BOOST_AUTO_TEST_CASE (test_create_destroy)
{
    error_handle_t *error_handle = NULL;
    error_handle = create_error_manager(&mock_lookup);

    delete_error_manager(error_handle);
}

struct Fixture{
    Fixture() {
        error_message = NULL;
        error_handle = create_error_manager(&mock_lookup);
    }
    ~Fixture() {
        delete_error_manager(error_handle);
        free(error_message);
    }
    int error;
    error_handle_t *error_handle;
    char *error_message;
};

BOOST_FIXTURE_TEST_CASE (test_set_clear, Fixture)
{
    error = set_error(error_handle, 100);
    BOOST_CHECK(error == 100);

    clear_error(error_handle);
    error = check_error(error_handle, &error_message);
    BOOST_CHECK(error == 0);
    BOOST_CHECK(error_message == NULL);
}

BOOST_FIXTURE_TEST_CASE(test_set_check, Fixture)
{
    error = set_error(error_handle, 100);
    BOOST_CHECK(error == 100);

    error = check_error(error_handle, &error_message);
    BOOST_CHECK(check_string(error_message, MESSAGE_STRING));
}

BOOST_AUTO_TEST_SUITE_END()


text:
// This file is part of the dune-xt project:
//   https://zivgitlab.uni-muenster.de/ag-ohlberger/dune-community/dune-xt
// Copyright 2009-2021 dune-xt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2012, 2014 - 2017)
//   René Fritze     (2009 - 2016, 2018 - 2020)
//   Sven Kaulmann   (2011)
//   Tobias Leibner  (2018, 2020)

#ifndef DUNE_XT_COMMON_PROFILER_HH
#define DUNE_XT_COMMON_PROFILER_HH

#ifndef DUNE_XT_COMMON_DO_PROFILE
#  define DUNE_XT_COMMON_DO_PROFILE 0
#endif

#ifndef DUNE_XT_COMMON_DO_TIMING
#  define DUNE_XT_COMMON_DO_TIMING 0
#endif

#include <array>
#include <atomic>
#include <ctime>
#include <iostream>
#include <map>
#include <memory>
#include <mutex>
#include <string>

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

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

#include <dune/xt/common/parallel/threadstorage.hh>
#include <utility>

namespace Dune::XT::Common {

class Timings;

//! XT::Profiler global instance
Timings& timings();

//! wraps name, start- and end time for one timing section
struct TimingData
{
private:
  std::shared_ptr<boost::timer::cpu_timer> timer_;

public:
  std::string name;

  explicit TimingData(std::string _name = "blank");

  void stop();

  using TimeType = boost::timer::nanosecond_type;
  using DeltaType = std::array<TimeType, 3>;

  /** \return array{wall,user,sys}: times elapsed since object construction in
   *milliseconds
   *  \note since typical resolutions for user+system time are 10-15ms the
   *nanosecond results are scaled accordingly
   **/
  DeltaType delta() const;
};

//! a utility class to time a limited scope of code
class ScopedTiming;

/** \brief simple inline timing class
 *  - User can set as many (even nested) named sections whose total (=system+user) time will be computed across all
 *    program instances.\n
 *  - Provides csv-conform output of process-averaged runtimes.
 **/
class Timings
{
  friend Timings& timings();

private:
  Timings();

  using KnownTimersMap = std::map<std::string, std::pair<std::atomic<bool>, UnsafePerThreadValue<TimingData>>>;
  //! section name -> seconds
  using DeltaMap = std::map<std::string, TimingData::DeltaType>;

  const TimingData& get_timing_data(std::string section_name) const;

public:
  ~Timings();

  void stop();

  //! set this to begin a named section
  void start(const std::string& section_name);

  //! stop named section's counter
  long stop(const std::string& section_name);

  //! set elapsed time back to 0 for section_name
  void reset(const std::string& section_name);

  //! get runtime of section in milliseconds
  TimingData::TimeType walltime(std::string section_name) const;
  //! get the full delta array
  TimingData::DeltaType delta(const std::string& section_name) const;

  /** creates one file local to each MPI-rank (no global averaging)
   *  one single rank-0 file with all combined/averaged measures
   ***/
  void output_per_rank(std::string csv_base) const;
  //! outputs walltime only w/o MPI-rank averaging
  void output_simple(std::ostream& out = std::cout) const;
  /** output all recorded measures
   * \note outputs average, min, max over all MPI processes associated to mpi_comm **/
  void output_all_measures(std::ostream& out = std::cout,
                           MPIHelper::MPICommunicator mpi_comm = Dune::MPIHelper::getCommunicator()) const;

  /// stops and resets all timers and data
  void reset();

  void set_outputdir(std::string dir);

private:
  DeltaMap commited_deltas_;
  //! runtime tables etc go there
  std::string output_dir_;

  KnownTimersMap known_timers_map_;
  const std::string csv_sep_;
  std::mutex mutex_;
};

//! global profiler object
DUNE_EXPORT inline Timings& timings()
{
  static Timings pf;
  return pf;
}

class ScopedTiming : public boost::noncopyable
{
protected:
  const std::string section_name_;

public:
  explicit inline ScopedTiming(std::string section_name)
    : section_name_(std::move(section_name))
  {
    timings().start(section_name_);
  }

  inline ~ScopedTiming()
  {
    timings().stop(section_name_);
  }
};

struct OutputScopedTiming : public ScopedTiming
{
  OutputScopedTiming(const std::string& section_name, std::ostream& out);

  ~OutputScopedTiming();

protected:
  std::ostream& out_;
};

} // namespace Dune::XT::Common

#define DXTC_TIMINGS Dune::XT::Common::timings()

#if DUNE_XT_COMMON_DO_TIMING
#  define DUNE_XT_COMMON_TIMING_SCOPE(section_name) [[maybe_unused]] Dune::XT::Common::ScopedTiming timer(section_name)
#else
#  define DUNE_XT_COMMON_TIMING_SCOPE(section_name)
#endif

#endif // DUNE_XT_COMMON_PROFILER_HH

ext: hh

max_stars_repo_name: dune-community/dune-xt

max_issues_repo_name: dune-community/dune-xt

max_forks_repo_name: dune-community/dune-xt