<commit_before>/*
 * Copyright (C) 2018-present ScyllaDB
 */

/*
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

#include <seastar/util/defer.hh>
#include <boost/range/adaptor/map.hpp>
#include "view_update_generator.hh"
#include "service/priority_manager.hh"
#include "utils/error_injection.hh"
#include "db/view/view_updating_consumer.hh"
#include "sstables/sstables.hh"
#include "readers/evictable.hh"

static logging::logger vug_logger("view_update_generator");

static inline void inject_failure(std::string_view operation) {
    utils::get_local_injector().inject(operation,
            [operation] { throw std::runtime_error(std::string(operation)); });
}

namespace db::view {

future<> view_update_generator::start() {
    thread_attributes attr;
    attr.sched_group = _db.get_streaming_scheduling_group();
    _started = seastar::async(std::move(attr), [this]() mutable {
        auto drop_sstable_references = defer([&] () noexcept {
            // Clear sstable references so sstables_manager::stop() doesn't hang.
            vug_logger.info("leaving {} unstaged sstables unprocessed",
                    _sstables_to_move.size(), _sstables_with_tables.size());
            _sstables_to_move.clear();
            _sstables_with_tables.clear();
        });
        while (!_as.abort_requested()) {
            if (_sstables_with_tables.empty()) {
                _pending_sstables.wait().get();
            }

            // To ensure we don't race with updates, move the entire content
            // into a local variable.
            auto sstables_with_tables = std::exchange(_sstables_with_tables, {});

            // If we got here, we will process all tables we know about so far eventually so there
            // is no starvation
            for (auto table_it = sstables_with_tables.begin(); table_it != sstables_with_tables.end(); table_it = sstables_with_tables.erase(table_it)) {
                auto& [t, sstables] = *table_it;
                schema_ptr s = t->schema();

                vug_logger.trace("Processing {}.{}: {} sstables", s->ks_name(), s->cf_name(), sstables.size());

                const auto num_sstables = sstables.size();

                try {
                    // Exploit the fact that sstables in the staging directory
                    // are usually non-overlapping and use a partitioned set for
                    // the read.
                    auto ssts = make_lw_shared<sstables::sstable_set>(sstables::make_partitioned_sstable_set(s, false));
                    for (auto& sst : sstables) {
                        ssts->insert(sst);
                    }

                    auto permit = _db.obtain_reader_permit(*t, "view_update_generator", db::no_timeout).get0();
                    auto ms = mutation_source([this, ssts] (
                                schema_ptr s,
                                reader_permit permit,
                                const dht::partition_range& pr,
                                const query::partition_slice& ps,
                                const io_priority_class& pc,
                                tracing::trace_state_ptr ts,
                                streamed_mutation::forwarding fwd_ms,
                                mutation_reader::forwarding fwd_mr) {
                        return ssts->make_range_sstable_reader(s, std::move(permit), pr, ps, pc, std::move(ts), fwd_ms, fwd_mr);
                    });
                    auto [staging_sstable_reader, staging_sstable_reader_handle] = make_manually_paused_evictable_reader_v2(
                            std::move(ms),
                            s,
                            permit,
                            query::full_partition_range,
                            s->full_slice(),
                            service::get_local_streaming_priority(),
                            nullptr,
                            ::mutation_reader::forwarding::no);

                    inject_failure("view_update_generator_consume_staging_sstable");
                    auto result = staging_sstable_reader.consume_in_thread(view_updating_consumer(s, std::move(permit), *t, sstables, _as, staging_sstable_reader_handle));
                    staging_sstable_reader.close().get();
                    if (result == stop_iteration::yes) {
                        break;
                    }
                } catch (...) {
                    vug_logger.warn("Processing {} failed for table {}:{}. Will retry...", s->ks_name(), s->cf_name(), std::current_exception());
                    // Need to add sstables back to the set so we can retry later. By now it may
                    // have had other updates.
                    std::move(sstables.begin(), sstables.end(), std::back_inserter(_sstables_with_tables[t]));
                    break;
                }
                try {
                    inject_failure("view_update_generator_collect_consumed_sstables");
                    // collect all staging sstables to move in a map, grouped by table.
                    std::move(sstables.begin(), sstables.end(), std::back_inserter(_sstables_to_move[t]));
                } catch (...) {
                    // Move from staging will be retried upon restart.
                    vug_logger.warn("Moving {} from staging failed: {}:{}. Ignoring...", s->ks_name(), s->cf_name(), std::current_exception());
                }
                _registration_sem.signal(num_sstables);
            }
            // For each table, move the processed staging sstables into the table's base dir.
            for (auto it = _sstables_to_move.begin(); it != _sstables_to_move.end(); ) {
                auto& [t, sstables] = *it;
                try {
                    inject_failure("view_update_generator_move_staging_sstable");
                    t->move_sstables_from_staging(sstables).get();
                } catch (...) {
                    // Move from staging will be retried upon restart.
                    vug_logger.warn("Moving some sstable from staging failed: {}. Ignoring...", std::current_exception());
                }
                it = _sstables_to_move.erase(it);
            }
        }
    });
    return make_ready_future<>();
}

future<> view_update_generator::stop() {
    _as.request_abort();
    _pending_sstables.signal();
    return std::move(_started).then([this] {
        _registration_sem.broken();
    });
}

bool view_update_generator::should_throttle() const {
    return !_started.available();
}

future<> view_update_generator::register_staging_sstable(sstables::shared_sstable sst, lw_shared_ptr<replica::table> table) {
    if (_as.abort_requested()) {
        return make_ready_future<>();
    }
    inject_failure("view_update_generator_registering_staging_sstable");
    _sstables_with_tables[table].push_back(std::move(sst));

    _pending_sstables.signal();
    if (should_throttle()) {
        return _registration_sem.wait(1);
    } else {
        _registration_sem.consume(1);
        return make_ready_future<>();
    }
}

void view_update_generator::setup_metrics() {
    namespace sm = seastar::metrics;

    _metrics.add_group("view_update_generator", {
        sm::make_gauge("pending_registrations", sm::description("Number of tasks waiting to register staging sstables"),
                [this] { return _registration_sem.waiters(); }),

        sm::make_gauge("queued_batches_count",
                sm::description("Number of sets of sstables queued for view update generation"),
                [this] { return _sstables_with_tables.size(); }),

        sm::make_gauge("sstables_to_move_count",
                sm::description("Number of sets of sstables which are already processed and wait to be moved from their staging directory"),
                [this] { return _sstables_to_move.size(); })
    });
}

void view_update_generator::discover_staging_sstables() {
    for (auto& x : _db.get_column_families()) {
        replica::table& t = *(x.second);
        for (auto sstables = t.get_sstables(); sstables::shared_sstable sst : *sstables) {
            if (sst->requires_view_building()) {
                _sstables_with_tables[t.shared_from_this()].push_back(std::move(sst));
                // we're at early stage here, no need to kick _pending_sstables (the
                // bulding fiber is not running), neither we can wait on the semaphore
                _registration_sem.consume(1);
            }
        }
    }
}

}
<commit_msg>view_update_generator: discover_staging_sstables: get shared table ptr earlier<commit_after>/*
 * Copyright (C) 2018-present ScyllaDB
 */

/*
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

#include <seastar/util/defer.hh>
#include <boost/range/adaptor/map.hpp>
#include "view_update_generator.hh"
#include "service/priority_manager.hh"
#include "utils/error_injection.hh"
#include "db/view/view_updating_consumer.hh"
#include "sstables/sstables.hh"
#include "readers/evictable.hh"

static logging::logger vug_logger("view_update_generator");

static inline void inject_failure(std::string_view operation) {
    utils::get_local_injector().inject(operation,
            [operation] { throw std::runtime_error(std::string(operation)); });
}

namespace db::view {

future<> view_update_generator::start() {
    thread_attributes attr;
    attr.sched_group = _db.get_streaming_scheduling_group();
    _started = seastar::async(std::move(attr), [this]() mutable {
        auto drop_sstable_references = defer([&] () noexcept {
            // Clear sstable references so sstables_manager::stop() doesn't hang.
            vug_logger.info("leaving {} unstaged sstables unprocessed",
                    _sstables_to_move.size(), _sstables_with_tables.size());
            _sstables_to_move.clear();
            _sstables_with_tables.clear();
        });
        while (!_as.abort_requested()) {
            if (_sstables_with_tables.empty()) {
                _pending_sstables.wait().get();
            }

            // To ensure we don't race with updates, move the entire content
            // into a local variable.
            auto sstables_with_tables = std::exchange(_sstables_with_tables, {});

            // If we got here, we will process all tables we know about so far eventually so there
            // is no starvation
            for (auto table_it = sstables_with_tables.begin(); table_it != sstables_with_tables.end(); table_it = sstables_with_tables.erase(table_it)) {
                auto& [t, sstables] = *table_it;
                schema_ptr s = t->schema();

                vug_logger.trace("Processing {}.{}: {} sstables", s->ks_name(), s->cf_name(), sstables.size());

                const auto num_sstables = sstables.size();

                try {
                    // Exploit the fact that sstables in the staging directory
                    // are usually non-overlapping and use a partitioned set for
                    // the read.
                    auto ssts = make_lw_shared<sstables::sstable_set>(sstables::make_partitioned_sstable_set(s, false));
                    for (auto& sst : sstables) {
                        ssts->insert(sst);
                    }

                    auto permit = _db.obtain_reader_permit(*t, "view_update_generator", db::no_timeout).get0();
                    auto ms = mutation_source([this, ssts] (
                                schema_ptr s,
                                reader_permit permit,
                                const dht::partition_range& pr,
                                const query::partition_slice& ps,
                                const io_priority_class& pc,
                                tracing::trace_state_ptr ts,
                                streamed_mutation::forwarding fwd_ms,
                                mutation_reader::forwarding fwd_mr) {
                        return ssts->make_range_sstable_reader(s, std::move(permit), pr, ps, pc, std::move(ts), fwd_ms, fwd_mr);
                    });
                    auto [staging_sstable_reader, staging_sstable_reader_handle] = make_manually_paused_evictable_reader_v2(
                            std::move(ms),
                            s,
                            permit,
                            query::full_partition_range,
                            s->full_slice(),
                            service::get_local_streaming_priority(),
                            nullptr,
                            ::mutation_reader::forwarding::no);

                    inject_failure("view_update_generator_consume_staging_sstable");
                    auto result = staging_sstable_reader.consume_in_thread(view_updating_consumer(s, std::move(permit), *t, sstables, _as, staging_sstable_reader_handle));
                    staging_sstable_reader.close().get();
                    if (result == stop_iteration::yes) {
                        break;
                    }
                } catch (...) {
                    vug_logger.warn("Processing {} failed for table {}:{}. Will retry...", s->ks_name(), s->cf_name(), std::current_exception());
                    // Need to add sstables back to the set so we can retry later. By now it may
                    // have had other updates.
                    std::move(sstables.begin(), sstables.end(), std::back_inserter(_sstables_with_tables[t]));
                    break;
                }
                try {
                    inject_failure("view_update_generator_collect_consumed_sstables");
                    // collect all staging sstables to move in a map, grouped by table.
                    std::move(sstables.begin(), sstables.end(), std::back_inserter(_sstables_to_move[t]));
                } catch (...) {
                    // Move from staging will be retried upon restart.
                    vug_logger.warn("Moving {} from staging failed: {}:{}. Ignoring...", s->ks_name(), s->cf_name(), std::current_exception());
                }
                _registration_sem.signal(num_sstables);
            }
            // For each table, move the processed staging sstables into the table's base dir.
            for (auto it = _sstables_to_move.begin(); it != _sstables_to_move.end(); ) {
                auto& [t, sstables] = *it;
                try {
                    inject_failure("view_update_generator_move_staging_sstable");
                    t->move_sstables_from_staging(sstables).get();
                } catch (...) {
                    // Move from staging will be retried upon restart.
                    vug_logger.warn("Moving some sstable from staging failed: {}. Ignoring...", std::current_exception());
                }
                it = _sstables_to_move.erase(it);
            }
        }
    });
    return make_ready_future<>();
}

future<> view_update_generator::stop() {
    _as.request_abort();
    _pending_sstables.signal();
    return std::move(_started).then([this] {
        _registration_sem.broken();
    });
}

bool view_update_generator::should_throttle() const {
    return !_started.available();
}

future<> view_update_generator::register_staging_sstable(sstables::shared_sstable sst, lw_shared_ptr<replica::table> table) {
    if (_as.abort_requested()) {
        return make_ready_future<>();
    }
    inject_failure("view_update_generator_registering_staging_sstable");
    _sstables_with_tables[table].push_back(std::move(sst));

    _pending_sstables.signal();
    if (should_throttle()) {
        return _registration_sem.wait(1);
    } else {
        _registration_sem.consume(1);
        return make_ready_future<>();
    }
}

void view_update_generator::setup_metrics() {
    namespace sm = seastar::metrics;

    _metrics.add_group("view_update_generator", {
        sm::make_gauge("pending_registrations", sm::description("Number of tasks waiting to register staging sstables"),
                [this] { return _registration_sem.waiters(); }),

        sm::make_gauge("queued_batches_count",
                sm::description("Number of sets of sstables queued for view update generation"),
                [this] { return _sstables_with_tables.size(); }),

        sm::make_gauge("sstables_to_move_count",
                sm::description("Number of sets of sstables which are already processed and wait to be moved from their staging directory"),
                [this] { return _sstables_to_move.size(); })
    });
}

void view_update_generator::discover_staging_sstables() {
    for (auto& x : _db.get_column_families()) {
        auto t = x.second->shared_from_this();
        for (auto sstables = t->get_sstables(); sstables::shared_sstable sst : *sstables) {
            if (sst->requires_view_building()) {
                _sstables_with_tables[t].push_back(std::move(sst));
                // we're at early stage here, no need to kick _pending_sstables (the
                // bulding fiber is not running), neither we can wait on the semaphore
                _registration_sem.consume(1);
            }
        }
    }
}

}
<|endoftext|>


<commit_before>//---------------------------------------------------------------------------
//      $Id$
//    Version: $Name$
//
//    Copyright (C) 2005, 2006, 2008, 2009 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//---------------------------------------------------------------------------

#include <base/index_set.h>

#ifdef DEAL_II_USE_TRILINOS
#  ifdef DEAL_II_COMPILER_SUPPORTS_MPI
#    include <Epetra_MpiComm.h>
#  endif
#  include <Epetra_SerialComm.h>
#  include <Epetra_Map.h>
#endif

DEAL_II_NAMESPACE_OPEN

void
IndexSet::do_compress () const
{
				   // see if any of the
				   // contiguous ranges can be
				   // merged. since they are sorted by
				   // their first index, determining
				   // overlap isn't all that hard
  for (std::vector<Range>::iterator
	 i = ranges.begin();
       i != ranges.end(); )
    {
      std::vector<Range>::iterator
	next = i;
      ++next;

      unsigned int first_index = i->begin;
      unsigned int last_index  = i->end;

				       // see if we can merge any of
				       // the following ranges
      bool can_merge = false;
      while (next != ranges.end() &&
	     (next->begin <= last_index))
	{
	  last_index = std::max (last_index, next->end);
	  ++next;
	  can_merge = true;
	}

      if (can_merge == true)
	{
					   // delete the old ranges
					   // and insert the new range
					   // in place of the previous
					   // one
	  *i = Range(first_index, last_index);
	  i = ranges.erase (i+1, next);
	}
      else
	++i;
    }

				   // now compute indices within set
  unsigned int next_index = 0;
  for (std::vector<Range>::iterator
	 i = ranges.begin();
       i != ranges.end();
       ++i)
    {
      i->nth_index_in_set = next_index;
      next_index += (i->end - i->begin);
    }
  is_compressed = true;

				   // check that next_index is
				   // correct. needs to be after the
				   // previous statement because we
				   // otherwise will get into an
				   // endless loop
  Assert (next_index == n_elements(), ExcInternalError());
}

IndexSet
IndexSet::operator & (const IndexSet &is) const
{
  Assert (size() == is.size(),
	  ExcDimensionMismatch (size(), is.size()));

  compress ();
  is.compress ();

  std::vector<Range>::const_iterator r1 = ranges.begin(),
				     r2 = is.ranges.begin();
  IndexSet result (size());

  while ((r1 != ranges.end())
	 &&
	 (r2 != is.ranges.end()))
    {
				       // if r1 and r2 do not overlap
				       // at all, then move the
				       // pointer that sits to the
				       // left of the other up by one
      if (r1->end <= r2->begin)
	++r1;
      else if (r2->end <= r1->begin)
	++r2;
      else
	{
					   // the ranges must overlap
					   // somehow
	  Assert (((r1->begin <= r2->begin) &&
		   (r1->end > r2->begin))
		  ||
		  ((r2->begin <= r1->begin) &&
		   (r2->end > r1->begin)),
		  ExcInternalError());

					   // add the overlapping
					   // range to the result
	  result.add_range (std::max (r1->begin,
				      r2->begin),
			    std::min (r1->end,
				      r2->end));

					   // now move that iterator
					   // that ends earlier one
					   // up. note that it has to
					   // be this one because a
					   // subsequent range may
					   // still have a chance of
					   // overlapping with the
					   // range that ends later
	  if (r1->end <= r2->end)
	    ++r1;
	  else
	    ++r2;
	}
    }

  result.compress ();
  return result;
}

IndexSet
IndexSet::get_view (const unsigned int begin,
		    const unsigned int end) const
{
  Assert (begin <= end,
	  ExcMessage ("End index needs to be larger or equal to begin index!"));
  Assert (end <= size(),
	  ExcMessage ("Given range exceeds index set dimension"));

  IndexSet result (end-begin);
  std::vector<Range>::const_iterator r1 = ranges.begin();

  while (r1 != ranges.end())
    {
      if ((r1->end > begin)
	  &&
	  (r1->begin < end))
	{
	  result.add_range (std::max(r1->begin, begin)-begin,
			    std::min(r1->end, end)-begin);

	}
      else
	if (r1->begin >= end)
	  break

      ++r1;
    }

  result.compress();
  return result;
}

#ifdef DEAL_II_USE_TRILINOS

Epetra_Map
IndexSet::make_trilinos_map (const MPI_Comm &communicator,
			     const bool overlapping) const
{
  compress ();

  if ((is_contiguous() == true) && (!overlapping))
    return Epetra_Map (size(),
		       n_elements(),
		       0,
#ifdef DEAL_II_COMPILER_SUPPORTS_MPI
		       Epetra_MpiComm(communicator));
#else
		       Epetra_SerialComm());
#endif
  else
    {
      std::vector<int> indices;
      indices.reserve(n_elements());
      for (std::vector<Range>::iterator
	     i = ranges.begin();
	   i != ranges.end();
	   ++i)
	for (unsigned int j=i->begin; j<i->end; ++j)
	  indices.push_back (j);
      Assert (indices.size() == n_elements(), ExcInternalError());

      return Epetra_Map (-1,
			 n_elements(),
			 &indices[0],
			 0,
#ifdef DEAL_II_COMPILER_SUPPORTS_MPI
			 Epetra_MpiComm(communicator));
#else
			 Epetra_SerialComm());
#endif
    }
}

#endif

DEAL_II_NAMESPACE_CLOSE
<commit_msg>Make sure it also compiles :-(<commit_after>//---------------------------------------------------------------------------
//      $Id$
//    Version: $Name$
//
//    Copyright (C) 2005, 2006, 2008, 2009 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//---------------------------------------------------------------------------

#include <base/index_set.h>

#ifdef DEAL_II_USE_TRILINOS
#  ifdef DEAL_II_COMPILER_SUPPORTS_MPI
#    include <Epetra_MpiComm.h>
#  endif
#  include <Epetra_SerialComm.h>
#  include <Epetra_Map.h>
#endif

DEAL_II_NAMESPACE_OPEN

void
IndexSet::do_compress () const
{
				   // see if any of the
				   // contiguous ranges can be
				   // merged. since they are sorted by
				   // their first index, determining
				   // overlap isn't all that hard
  for (std::vector<Range>::iterator
	 i = ranges.begin();
       i != ranges.end(); )
    {
      std::vector<Range>::iterator
	next = i;
      ++next;

      unsigned int first_index = i->begin;
      unsigned int last_index  = i->end;

				       // see if we can merge any of
				       // the following ranges
      bool can_merge = false;
      while (next != ranges.end() &&
	     (next->begin <= last_index))
	{
	  last_index = std::max (last_index, next->end);
	  ++next;
	  can_merge = true;
	}

      if (can_merge == true)
	{
					   // delete the old ranges
					   // and insert the new range
					   // in place of the previous
					   // one
	  *i = Range(first_index, last_index);
	  i = ranges.erase (i+1, next);
	}
      else
	++i;
    }

				   // now compute indices within set
  unsigned int next_index = 0;
  for (std::vector<Range>::iterator
	 i = ranges.begin();
       i != ranges.end();
       ++i)
    {
      i->nth_index_in_set = next_index;
      next_index += (i->end - i->begin);
    }
  is_compressed = true;

				   // check that next_index is
				   // correct. needs to be after the
				   // previous statement because we
				   // otherwise will get into an
				   // endless loop
  Assert (next_index == n_elements(), ExcInternalError());
}

IndexSet
IndexSet::operator & (const IndexSet &is) const
{
  Assert (size() == is.size(),
	  ExcDimensionMismatch (size(), is.size()));

  compress ();
  is.compress ();

  std::vector<Range>::const_iterator r1 = ranges.begin(),
				     r2 = is.ranges.begin();
  IndexSet result (size());

  while ((r1 != ranges.end())
	 &&
	 (r2 != is.ranges.end()))
    {
				       // if r1 and r2 do not overlap
				       // at all, then move the
				       // pointer that sits to the
				       // left of the other up by one
      if (r1->end <= r2->begin)
	++r1;
      else if (r2->end <= r1->begin)
	++r2;
      else
	{
					   // the ranges must overlap
					   // somehow
	  Assert (((r1->begin <= r2->begin) &&
		   (r1->end > r2->begin))
		  ||
		  ((r2->begin <= r1->begin) &&
		   (r2->end > r1->begin)),
		  ExcInternalError());

					   // add the overlapping
					   // range to the result
	  result.add_range (std::max (r1->begin,
				      r2->begin),
			    std::min (r1->end,
				      r2->end));

					   // now move that iterator
					   // that ends earlier one
					   // up. note that it has to
					   // be this one because a
					   // subsequent range may
					   // still have a chance of
					   // overlapping with the
					   // range that ends later
	  if (r1->end <= r2->end)
	    ++r1;
	  else
	    ++r2;
	}
    }

  result.compress ();
  return result;
}

IndexSet
IndexSet::get_view (const unsigned int begin,
		    const unsigned int end) const
{
  Assert (begin <= end,
	  ExcMessage ("End index needs to be larger or equal to begin index!"));
  Assert (end <= size(),
	  ExcMessage ("Given range exceeds index set dimension"));

  IndexSet result (end-begin);
  std::vector<Range>::const_iterator r1 = ranges.begin();

  while (r1 != ranges.end())
    {
      if ((r1->end > begin)
	  &&
	  (r1->begin < end))
	{
	  result.add_range (std::max(r1->begin, begin)-begin,
			    std::min(r1->end, end)-begin);

	}
      else
	if (r1->begin >= end)
	  break;

      ++r1;
    }

  result.compress();
  return result;
}

#ifdef DEAL_II_USE_TRILINOS

Epetra_Map
IndexSet::make_trilinos_map (const MPI_Comm &communicator,
			     const bool overlapping) const
{
  compress ();

  if ((is_contiguous() == true) && (!overlapping))
    return Epetra_Map (size(),
		       n_elements(),
		       0,
#ifdef DEAL_II_COMPILER_SUPPORTS_MPI
		       Epetra_MpiComm(communicator));
#else
		       Epetra_SerialComm());
#endif
  else
    {
      std::vector<int> indices;
      indices.reserve(n_elements());
      for (std::vector<Range>::iterator
	     i = ranges.begin();
	   i != ranges.end();
	   ++i)
	for (unsigned int j=i->begin; j<i->end; ++j)
	  indices.push_back (j);
      Assert (indices.size() == n_elements(), ExcInternalError());

      return Epetra_Map (-1,
			 n_elements(),
			 &indices[0],
			 0,
#ifdef DEAL_II_COMPILER_SUPPORTS_MPI
			 Epetra_MpiComm(communicator));
#else
			 Epetra_SerialComm());
#endif
    }
}

#endif

DEAL_II_NAMESPACE_CLOSE
<|endoftext|>


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

 Program:   Visualization Toolkit
 Module:    vtkStructuredGridConnectivity.cxx

 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
 All rights reserved.
 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notice for more information.

 =========================================================================*/
#include "vtkStructuredGridConnectivity.h"
#include "vtkObjectFactory.h"
#include "vtkMeshProperty.h"
#include "vtkMeshPropertyEncoder.h"
#include "vtkStructuredData.h"
#include "vtkStructuredExtent.h"
#include "vtkIdList.h"
#include "vtkStructuredNeighbor.h"

#include <set>
#include <vector>
#include <algorithm>

#define NO_OVERLAP   0
#define NODE_OVERLAP 1
#define EDGE_OVERLAP 2

vtkStandardNewMacro( vtkStructuredGridConnectivity );

//------------------------------------------------------------------------------
vtkStructuredGridConnectivity::vtkStructuredGridConnectivity()
{
  this->DataDescription = -1;
  this->NumberOfGrids   = 0;
  this->WholeExtent[0]  = this->WholeExtent[1] = this->WholeExtent[2] =
  this->WholeExtent[3]  = this->WholeExtent[4] = this->WholeExtent[5] = -1;
  this->GridExtents.clear();
}

//------------------------------------------------------------------------------
vtkStructuredGridConnectivity::~vtkStructuredGridConnectivity()
{
  this->GridExtents.clear();
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::PrintSelf(std::ostream& os,vtkIndent indent)
{
  this->Superclass::PrintSelf( os, indent );
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::RegisterGrid(const int gridID,int ext[6])
{
  assert( "pre: gridID out-of-bounds!" &&
           (gridID >= 0  && gridID < this->NumberOfGrids) );
  for( int i=0; i < 6; ++i )
    this->GridExtents[ gridID*6+i ] = ext[i];
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::GetGridExtent(const int gridID, int ext[6])
{
  assert( "pre: gridID out-of-bounds!" &&
          (gridID >= 0  && gridID < this->NumberOfGrids) );
  for( int i=0; i < 6; ++i )
    ext[i] = this->GridExtents[ gridID*6+i ];
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::AcquireDataDescription()
{
  if( this->DataDescription != -1 )
    return;

  int dims[3];
  vtkStructuredExtent::GetDimensions( this->WholeExtent, dims );
  this->DataDescription = vtkStructuredData::GetDataDescription( dims );
  assert( "pre: Error acquiring data description" &&
           (this->DataDescription >= 0) );
}

//------------------------------------------------------------------------------
vtkIdList* vtkStructuredGridConnectivity::GetNeighbors(
    const int gridID,int *extents )
{
  assert( "pre: input extents array is NULL" && (extents != NULL) );

  int N = this->GetNumberOfNeighbors( gridID );
  if( N < 1 ) return NULL;

  vtkIdList *neiList = vtkIdList::New();
  neiList->SetNumberOfIds( N );

  unsigned int nei=0;
  for( ; nei < this->Neighbors[ gridID ].size(); ++nei )
    {
    vtkIdType neiId = this->Neighbors[ gridID ][ nei ].NeighborID;
    neiList->SetId( nei, neiId );
    for( int i=0; i < 6; ++i  )
      extents[ nei*6+i ] = this->Neighbors[ gridID ][ nei ].OverlapExtent[ i ];
    } // END for all neighbors

  assert( "post: N==neiList.size()" &&
          (N == neiList->GetNumberOfIds()) );
  return( neiList );
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::ComputeNeighbors()
{
  this->AcquireDataDescription( );
  if( this->DataDescription == VTK_EMPTY ||
      this->DataDescription == VTK_SINGLE_POINT )
      return;

  for( int i=0; i < this->NumberOfGrids; ++i )
    {
    for( int j=i+1; j < this->NumberOfGrids; ++j )
      {
      this->EstablishNeighbors(i,j);
      } // END for all j
    } // END for all i
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::SearchNeighbors(
    const int gridID, const int i, const int j, const int k,
    vtkIdList *neiList )
{
  assert( "pre: neiList should not be NULL" && (neiList != NULL) );
  assert( "pre: gridID is out-of-bounds" &&
           ( (gridID >= 0) && (gridID < this->NumberOfGrids) ) );

  for( unsigned int nei=0; nei < this->Neighbors[ gridID ].size(); ++nei )
    {
    vtkStructuredNeighbor *myNei = &this->Neighbors[ gridID ][ nei ];
    assert( "pre: myNei != NULL" && (myNei != NULL) );

    if( this->IsNodeWithinExtent( i, j, k, myNei->OverlapExtent) )
      neiList->InsertNextId( myNei->NeighborID );
    } // END for all neis
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::MarkNodeProperty(
    const int gridID, const int i, const int j, const int k,
    int ext[6], unsigned char &p )
{
  vtkMeshPropertyEncoder::Reset( p );

  if( this->IsNodeInterior( i, j, k, ext ) )
    {
    vtkMeshPropertyEncoder::SetProperty( p,VTKNodeProperties::INTERNAL );
    }
  else
    {
    if( this->IsNodeOnBoundary(i,j,k) )
      {
      vtkMeshPropertyEncoder::SetProperty( p,VTKNodeProperties::BOUNDARY );
      }

    // Figure out if the point is shared and who owns the point
    vtkIdList *neiList = vtkIdList::New();
    this->SearchNeighbors( gridID, i, j, k, neiList );

    if( neiList->GetNumberOfIds() > 0 )
      {
      std::cout << "Mark node as shared!" << std::endl;
      std::cout.flush();

      vtkMeshPropertyEncoder::SetProperty( p, VTKNodeProperties::SHARED );

      for( vtkIdType nei=0; nei < neiList->GetNumberOfIds(); ++nei )
        {
        // If my gridID is not the smallest gridID that shares the point, then
        // I don't own the point.
        // The convention is that the grid with the smallest gridID will own the
        // point and all other grids should IGNORE it when computing statistics etc.
        if( gridID > neiList->GetId( nei ) )
          {
          std::cout << "Mark node as IGNORE!\n";
          std::cout.flush();

          vtkMeshPropertyEncoder::SetProperty( p,VTKNodeProperties::IGNORE );
          break;
          }
        } //END for all neis
      } // END if  shared
    neiList->Delete();
    }
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::FillMeshPropertyArrays(
    const int gridID, unsigned char *nodesArray, unsigned char *cellsArray )
{
  assert( "pre: Nodes array is not NULL" && (nodesArray != NULL) );
  assert( "pre: Cell array is not NULL" && (cellsArray != NULL) );

  int GridExtent[6];
  this->GetGridExtent( gridID, GridExtent );

  int ijkmin[3];
  ijkmin[0] = GridExtent[0];
  ijkmin[1] = GridExtent[2];
  ijkmin[2] = GridExtent[4];

  int dims[3];
  vtkStructuredExtent::GetDimensions( GridExtent, dims );

  for( int i=GridExtent[0]; i <= GridExtent[1]; ++i )
    {
    for( int j=GridExtent[2]; j <= GridExtent[3]; ++j )
      {
      for( int k=GridExtent[4]; k <= GridExtent[5]; ++k )
        {
        // Convert global indices to local indices
        int li = i - ijkmin[0];
        int lj = j - ijkmin[1];
        int lk = k - ijkmin[2];

        int idx = vtkStructuredData::ComputePointId( dims, li, lj, lk );
        this->MarkNodeProperty( gridID,i,j,k,GridExtent,nodesArray[idx] );
        } // END for all k
      } // END for all j
    } // END for all i
}

//------------------------------------------------------------------------------
bool vtkStructuredGridConnectivity::IsNodeOnBoundary(
    const int i, const int j, const int k )
{
  // TODO: Add support for 2-D and 1-D cases
  if( i==this->WholeExtent[0] || i==this->WholeExtent[1] ||
      j==this->WholeExtent[2] || j==this->WholeExtent[3] ||
      k==this->WholeExtent[4] || k==this->WholeExtent[5] )
      return true;
  return false;
}

//------------------------------------------------------------------------------
bool vtkStructuredGridConnectivity::IsNodeInterior(
    const int i, const int j, const int k,
    int GridExtent[6] )
{
  // TODO: Add support for 2-D and 1-D cases
  if( (GridExtent[0] < i) && (i < GridExtent[1]) &&
      (GridExtent[2] < j) && (j < GridExtent[3]) &&
      (GridExtent[4] < k) && (k < GridExtent[5])    )
      return true;
  return false;
}

//------------------------------------------------------------------------------
bool vtkStructuredGridConnectivity::IsNodeWithinExtent(
    const int i, const int j, const int k,
    int GridExtent[6] )
{
  // TODO: Add support for 2-D and 1-D cases
  if( (GridExtent[0] <= i) && (i <= GridExtent[1] ) &&
      (GridExtent[2] <= j) && (j <= GridExtent[3] ) &&
      (GridExtent[4] <= k) && (k <= GridExtent[5] ) )
      return true;
  return false;
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::EstablishNeighbors(const int i,const int j)
{
  assert( "pre: i < j" && (i < j) );

  int iGridExtent[6];
  int jGridExtent[6];
  this->GetGridExtent( i, iGridExtent );
  this->GetGridExtent( j, jGridExtent );

  // A 3-tuple that defines the grid orientation of the form {i,j,k} where
  // i=0;, j=1, k=2. For example, let's say that we want to define the
  // orientation to be in the XZ plane, then, orientation  array would be
  // constructed as follows: {0,2 -1}, where -1 indicates a NIL value.
  int orientation[3];

  // A place holder for setting up ndim, which store the dimensionality of
  // the data.
  int ndim = 3;

  switch( this->DataDescription )
    {
    case VTK_X_LINE:
      ndim           =  1;
      orientation[0] =  0;
      orientation[1] = -1;
      orientation[2] = -1;
      break;
    case VTK_Y_LINE:
      ndim           =  1;
      orientation[0] =  1;
      orientation[1] = -1;
      orientation[2] = -1;
      break;
    case VTK_Z_LINE:
      ndim           =  1;
      orientation[0] =  2;
      orientation[1] = -1;
      orientation[2] = -1;
      break;
    case VTK_XY_PLANE:
      ndim           =  2;
      orientation[0] =  0;
      orientation[1] =  1;
      orientation[2] = -1;
      break;
    case VTK_YZ_PLANE:
      ndim           =  2;
      orientation[0] =  1;
      orientation[1] =  2;
      orientation[2] = -1;
      break;
    case VTK_XZ_PLANE:
      ndim           =  2;
      orientation[0] =  0;
      orientation[1] =  2;
      orientation[2] = -1;
      break;
    case VTK_XYZ_GRID:
      ndim           =  3;
      orientation[0] =  0;
      orientation[1] =  1;
      orientation[2] =  2;
      break;
    default:
      assert( "pre: Undefined data-description!" && false );
    } // END switch

  this->DetectNeighbors( i, j, iGridExtent, jGridExtent, orientation, ndim );
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::DetectNeighbors(
    const int i, const int j,
    int ex1[6], int ex2[6], int orientation[3], int ndim )
{
  std::vector< int > status;
  status.resize( ndim );

  int A[2];
  int B[2];
  int overlap[2];

  int overlapExtent[6];
  for( int ii=0; ii < 6; ++ii )
    overlapExtent[ ii ] = 0;

  int dim = 0;
  int idx = 0;
  for( dim=0; dim < ndim; ++dim )
    {
    idx           = orientation[dim];
    A[0]          = ex1[ idx*2 ];
    A[1]          = ex1[ idx*2+1 ];
    B[0]          = ex2[ idx*2 ];
    B[1]          = ex2[ idx*2+1 ];
    status[ idx ] = this->IntervalOverlap( A, B, overlap );
    if( status[idx] == NO_OVERLAP )
      return; /* No neighbors */
    overlapExtent[ idx*2 ]   = overlap[0];
    overlapExtent[ idx*2+1 ] = overlap[1];
    } // END for all dimensions

  this->SetNeighbors( i, j, overlapExtent );
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::SetNeighbors(
            const int i, const int j, int overlapExtent[6] )
{
  vtkStructuredNeighbor Ni2j( j, overlapExtent );
  vtkStructuredNeighbor Nj2i( i, overlapExtent );

  this->Neighbors[ i ].push_back( Ni2j );
  this->Neighbors[ j ].push_back( Nj2i );

// BEGIN DEBUG
  int iGridExtent[6];
  int jGridExtent[6];
  this->GetGridExtent( i, iGridExtent );
  this->GetGridExtent( j, jGridExtent );

  std::cout << "===\n";
  this->PrintExtent( iGridExtent );
  this->PrintExtent( jGridExtent );
  std::cout << "\n\n";
  this->PrintExtent( overlapExtent );
// END DEBUG

}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::PrintExtent( int ex[6] )
{
  for( int i=0; i < 3; ++i )
    std::cout << " [" << ex[i*2] << ", " << ex[i*2+1] << "] ";
  std::cout << std::endl;
  std::cout.flush();
}

//------------------------------------------------------------------------------
int vtkStructuredGridConnectivity::IntervalOverlap(
                    int A[2], int B[2], int overlap[2] )
{
  int rc = NO_OVERLAP;

  // STEP 0: Initialize overlap
  for( int i=0; i < 2; i++ )
    overlap[i] = -1;

  // STEP 1: Allocate internal intersection vector. Note, since the cardinality
  // of A,B is 2, the intersection vector can be at most of size 2.
  std::vector< int > intersection;
  intersection.resize( 2 );

  // STEP 2: Compute intersection
  std::vector< int >::iterator it;
  it = std::set_intersection( A, A+2, B, B+2, intersection.begin() );

  // STEP 3: Find number of intersections and overlap extent
  int N = static_cast< int >( it-intersection.begin() );

  switch( N )
    {
    case 0:
      rc = NO_OVERLAP;
      overlap[ 0 ] = overlap[ 1 ] = -1;
      break;
    case 1:
      rc = NODE_OVERLAP;
      overlap[0] = overlap[1] = intersection[0];
      break;
    case 2:
      rc = EDGE_OVERLAP;
      overlap[0] = intersection[0];
      overlap[1] = intersection[1];
      break;
    default:
      rc = NO_OVERLAP;
      overlap[ 0 ] = overlap[ 1 ] = -1;
      vtkErrorMacro( "Code should not reach here!" )
    }

  return( rc );
}

<commit_msg>DEBUG: Remove debug statements<commit_after>/*=========================================================================

 Program:   Visualization Toolkit
 Module:    vtkStructuredGridConnectivity.cxx

 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
 All rights reserved.
 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

 This software is distributed WITHOUT ANY WARRANTY; without even
 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 PURPOSE.  See the above copyright notice for more information.

 =========================================================================*/
#include "vtkStructuredGridConnectivity.h"
#include "vtkObjectFactory.h"
#include "vtkMeshProperty.h"
#include "vtkMeshPropertyEncoder.h"
#include "vtkStructuredData.h"
#include "vtkStructuredExtent.h"
#include "vtkIdList.h"
#include "vtkStructuredNeighbor.h"

#include <set>
#include <vector>
#include <algorithm>

#define NO_OVERLAP   0
#define NODE_OVERLAP 1
#define EDGE_OVERLAP 2

vtkStandardNewMacro( vtkStructuredGridConnectivity );

//------------------------------------------------------------------------------
vtkStructuredGridConnectivity::vtkStructuredGridConnectivity()
{
  this->DataDescription = -1;
  this->NumberOfGrids   = 0;
  this->WholeExtent[0]  = this->WholeExtent[1] = this->WholeExtent[2] =
  this->WholeExtent[3]  = this->WholeExtent[4] = this->WholeExtent[5] = -1;
  this->GridExtents.clear();
}

//------------------------------------------------------------------------------
vtkStructuredGridConnectivity::~vtkStructuredGridConnectivity()
{
  this->GridExtents.clear();
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::PrintSelf(std::ostream& os,vtkIndent indent)
{
  this->Superclass::PrintSelf( os, indent );
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::RegisterGrid(const int gridID,int ext[6])
{
  assert( "pre: gridID out-of-bounds!" &&
           (gridID >= 0  && gridID < this->NumberOfGrids) );
  for( int i=0; i < 6; ++i )
    this->GridExtents[ gridID*6+i ] = ext[i];
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::GetGridExtent(const int gridID, int ext[6])
{
  assert( "pre: gridID out-of-bounds!" &&
          (gridID >= 0  && gridID < this->NumberOfGrids) );
  for( int i=0; i < 6; ++i )
    ext[i] = this->GridExtents[ gridID*6+i ];
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::AcquireDataDescription()
{
  if( this->DataDescription != -1 )
    return;

  int dims[3];
  vtkStructuredExtent::GetDimensions( this->WholeExtent, dims );
  this->DataDescription = vtkStructuredData::GetDataDescription( dims );
  assert( "pre: Error acquiring data description" &&
           (this->DataDescription >= 0) );
}

//------------------------------------------------------------------------------
vtkIdList* vtkStructuredGridConnectivity::GetNeighbors(
    const int gridID,int *extents )
{
  assert( "pre: input extents array is NULL" && (extents != NULL) );

  int N = this->GetNumberOfNeighbors( gridID );
  if( N < 1 ) return NULL;

  vtkIdList *neiList = vtkIdList::New();
  neiList->SetNumberOfIds( N );

  unsigned int nei=0;
  for( ; nei < this->Neighbors[ gridID ].size(); ++nei )
    {
    vtkIdType neiId = this->Neighbors[ gridID ][ nei ].NeighborID;
    neiList->SetId( nei, neiId );
    for( int i=0; i < 6; ++i  )
      extents[ nei*6+i ] = this->Neighbors[ gridID ][ nei ].OverlapExtent[ i ];
    } // END for all neighbors

  assert( "post: N==neiList.size()" &&
          (N == neiList->GetNumberOfIds()) );
  return( neiList );
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::ComputeNeighbors()
{
  this->AcquireDataDescription( );
  if( this->DataDescription == VTK_EMPTY ||
      this->DataDescription == VTK_SINGLE_POINT )
      return;

  for( int i=0; i < this->NumberOfGrids; ++i )
    {
    for( int j=i+1; j < this->NumberOfGrids; ++j )
      {
      this->EstablishNeighbors(i,j);
      } // END for all j
    } // END for all i
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::SearchNeighbors(
    const int gridID, const int i, const int j, const int k,
    vtkIdList *neiList )
{
  assert( "pre: neiList should not be NULL" && (neiList != NULL) );
  assert( "pre: gridID is out-of-bounds" &&
           ( (gridID >= 0) && (gridID < this->NumberOfGrids) ) );

  for( unsigned int nei=0; nei < this->Neighbors[ gridID ].size(); ++nei )
    {
    vtkStructuredNeighbor *myNei = &this->Neighbors[ gridID ][ nei ];
    assert( "pre: myNei != NULL" && (myNei != NULL) );

    if( this->IsNodeWithinExtent( i, j, k, myNei->OverlapExtent) )
      neiList->InsertNextId( myNei->NeighborID );
    } // END for all neis
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::MarkNodeProperty(
    const int gridID, const int i, const int j, const int k,
    int ext[6], unsigned char &p )
{
  vtkMeshPropertyEncoder::Reset( p );

  if( this->IsNodeInterior( i, j, k, ext ) )
    {
    vtkMeshPropertyEncoder::SetProperty( p,VTKNodeProperties::INTERNAL );
    }
  else
    {
    if( this->IsNodeOnBoundary(i,j,k) )
      {
      vtkMeshPropertyEncoder::SetProperty( p,VTKNodeProperties::BOUNDARY );
      }

    // Figure out if the point is shared and who owns the point
    vtkIdList *neiList = vtkIdList::New();
    this->SearchNeighbors( gridID, i, j, k, neiList );

    if( neiList->GetNumberOfIds() > 0 )
      {
      vtkMeshPropertyEncoder::SetProperty( p, VTKNodeProperties::SHARED );

      for( vtkIdType nei=0; nei < neiList->GetNumberOfIds(); ++nei )
        {
        // If my gridID is not the smallest gridID that shares the point, then
        // I don't own the point.
        // The convention is that the grid with the smallest gridID will own the
        // point and all other grids should IGNORE it when computing statistics etc.
        if( gridID > neiList->GetId( nei ) )
          {
          vtkMeshPropertyEncoder::SetProperty( p,VTKNodeProperties::IGNORE );
          break;
          }
        } //END for all neis
      } // END if  shared
    neiList->Delete();
    }
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::FillMeshPropertyArrays(
    const int gridID, unsigned char *nodesArray, unsigned char *cellsArray )
{
  assert( "pre: Nodes array is not NULL" && (nodesArray != NULL) );
  assert( "pre: Cell array is not NULL" && (cellsArray != NULL) );

  int GridExtent[6];
  this->GetGridExtent( gridID, GridExtent );

  int ijkmin[3];
  ijkmin[0] = GridExtent[0];
  ijkmin[1] = GridExtent[2];
  ijkmin[2] = GridExtent[4];

  int dims[3];
  vtkStructuredExtent::GetDimensions( GridExtent, dims );

  for( int i=GridExtent[0]; i <= GridExtent[1]; ++i )
    {
    for( int j=GridExtent[2]; j <= GridExtent[3]; ++j )
      {
      for( int k=GridExtent[4]; k <= GridExtent[5]; ++k )
        {
        // Convert global indices to local indices
        int li = i - ijkmin[0];
        int lj = j - ijkmin[1];
        int lk = k - ijkmin[2];

        int idx = vtkStructuredData::ComputePointId( dims, li, lj, lk );
        this->MarkNodeProperty( gridID,i,j,k,GridExtent,nodesArray[idx] );
        } // END for all k
      } // END for all j
    } // END for all i
}

//------------------------------------------------------------------------------
bool vtkStructuredGridConnectivity::IsNodeOnBoundary(
    const int i, const int j, const int k )
{
  // TODO: Add support for 2-D and 1-D cases
  if( i==this->WholeExtent[0] || i==this->WholeExtent[1] ||
      j==this->WholeExtent[2] || j==this->WholeExtent[3] ||
      k==this->WholeExtent[4] || k==this->WholeExtent[5] )
      return true;
  return false;
}

//------------------------------------------------------------------------------
bool vtkStructuredGridConnectivity::IsNodeInterior(
    const int i, const int j, const int k,
    int GridExtent[6] )
{
  // TODO: Add support for 2-D and 1-D cases
  if( (GridExtent[0] < i) && (i < GridExtent[1]) &&
      (GridExtent[2] < j) && (j < GridExtent[3]) &&
      (GridExtent[4] < k) && (k < GridExtent[5])    )
      return true;
  return false;
}

//------------------------------------------------------------------------------
bool vtkStructuredGridConnectivity::IsNodeWithinExtent(
    const int i, const int j, const int k,
    int GridExtent[6] )
{
  // TODO: Add support for 2-D and 1-D cases
  if( (GridExtent[0] <= i) && (i <= GridExtent[1] ) &&
      (GridExtent[2] <= j) && (j <= GridExtent[3] ) &&
      (GridExtent[4] <= k) && (k <= GridExtent[5] ) )
      return true;
  return false;
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::EstablishNeighbors(const int i,const int j)
{
  assert( "pre: i < j" && (i < j) );

  int iGridExtent[6];
  int jGridExtent[6];
  this->GetGridExtent( i, iGridExtent );
  this->GetGridExtent( j, jGridExtent );

  // A 3-tuple that defines the grid orientation of the form {i,j,k} where
  // i=0;, j=1, k=2. For example, let's say that we want to define the
  // orientation to be in the XZ plane, then, orientation  array would be
  // constructed as follows: {0,2 -1}, where -1 indicates a NIL value.
  int orientation[3];

  // A place holder for setting up ndim, which store the dimensionality of
  // the data.
  int ndim = 3;

  switch( this->DataDescription )
    {
    case VTK_X_LINE:
      ndim           =  1;
      orientation[0] =  0;
      orientation[1] = -1;
      orientation[2] = -1;
      break;
    case VTK_Y_LINE:
      ndim           =  1;
      orientation[0] =  1;
      orientation[1] = -1;
      orientation[2] = -1;
      break;
    case VTK_Z_LINE:
      ndim           =  1;
      orientation[0] =  2;
      orientation[1] = -1;
      orientation[2] = -1;
      break;
    case VTK_XY_PLANE:
      ndim           =  2;
      orientation[0] =  0;
      orientation[1] =  1;
      orientation[2] = -1;
      break;
    case VTK_YZ_PLANE:
      ndim           =  2;
      orientation[0] =  1;
      orientation[1] =  2;
      orientation[2] = -1;
      break;
    case VTK_XZ_PLANE:
      ndim           =  2;
      orientation[0] =  0;
      orientation[1] =  2;
      orientation[2] = -1;
      break;
    case VTK_XYZ_GRID:
      ndim           =  3;
      orientation[0] =  0;
      orientation[1] =  1;
      orientation[2] =  2;
      break;
    default:
      assert( "pre: Undefined data-description!" && false );
    } // END switch

  this->DetectNeighbors( i, j, iGridExtent, jGridExtent, orientation, ndim );
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::DetectNeighbors(
    const int i, const int j,
    int ex1[6], int ex2[6], int orientation[3], int ndim )
{
  std::vector< int > status;
  status.resize( ndim );

  int A[2];
  int B[2];
  int overlap[2];

  int overlapExtent[6];
  for( int ii=0; ii < 6; ++ii )
    overlapExtent[ ii ] = 0;

  int dim = 0;
  int idx = 0;
  for( dim=0; dim < ndim; ++dim )
    {
    idx           = orientation[dim];
    A[0]          = ex1[ idx*2 ];
    A[1]          = ex1[ idx*2+1 ];
    B[0]          = ex2[ idx*2 ];
    B[1]          = ex2[ idx*2+1 ];
    status[ idx ] = this->IntervalOverlap( A, B, overlap );
    if( status[idx] == NO_OVERLAP )
      return; /* No neighbors */
    overlapExtent[ idx*2 ]   = overlap[0];
    overlapExtent[ idx*2+1 ] = overlap[1];
    } // END for all dimensions

  this->SetNeighbors( i, j, overlapExtent );
}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::SetNeighbors(
            const int i, const int j, int overlapExtent[6] )
{
  vtkStructuredNeighbor Ni2j( j, overlapExtent );
  vtkStructuredNeighbor Nj2i( i, overlapExtent );

  this->Neighbors[ i ].push_back( Ni2j );
  this->Neighbors[ j ].push_back( Nj2i );

// BEGIN DEBUG
  int iGridExtent[6];
  int jGridExtent[6];
  this->GetGridExtent( i, iGridExtent );
  this->GetGridExtent( j, jGridExtent );

  std::cout << "===\n";
  this->PrintExtent( iGridExtent );
  this->PrintExtent( jGridExtent );
  std::cout << "\n\n";
  this->PrintExtent( overlapExtent );
// END DEBUG

}

//------------------------------------------------------------------------------
void vtkStructuredGridConnectivity::PrintExtent( int ex[6] )
{
  for( int i=0; i < 3; ++i )
    std::cout << " [" << ex[i*2] << ", " << ex[i*2+1] << "] ";
  std::cout << std::endl;
  std::cout.flush();
}

//------------------------------------------------------------------------------
int vtkStructuredGridConnectivity::IntervalOverlap(
                    int A[2], int B[2], int overlap[2] )
{
  int rc = NO_OVERLAP;

  // STEP 0: Initialize overlap
  for( int i=0; i < 2; i++ )
    overlap[i] = -1;

  // STEP 1: Allocate internal intersection vector. Note, since the cardinality
  // of A,B is 2, the intersection vector can be at most of size 2.
  std::vector< int > intersection;
  intersection.resize( 2 );

  // STEP 2: Compute intersection
  std::vector< int >::iterator it;
  it = std::set_intersection( A, A+2, B, B+2, intersection.begin() );

  // STEP 3: Find number of intersections and overlap extent
  int N = static_cast< int >( it-intersection.begin() );

  switch( N )
    {
    case 0:
      rc = NO_OVERLAP;
      overlap[ 0 ] = overlap[ 1 ] = -1;
      break;
    case 1:
      rc = NODE_OVERLAP;
      overlap[0] = overlap[1] = intersection[0];
      break;
    case 2:
      rc = EDGE_OVERLAP;
      overlap[0] = intersection[0];
      overlap[1] = intersection[1];
      break;
    default:
      rc = NO_OVERLAP;
      overlap[ 0 ] = overlap[ 1 ] = -1;
      vtkErrorMacro( "Code should not reach here!" )
    }

  return( rc );
}

<|endoftext|>


<commit_before>//---------------------------------------------------------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2011 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//---------------------------------------------------------------------------

#include <deal.II/base/logstream.h>
#include <deal.II/base/job_identifier.h>
#include <deal.II/base/memory_consumption.h>
#include <deal.II/base/thread_management.h>

// include sys/resource.h for rusage(). Mac OS X needs sys/time.h then
// as well (strange), so include that, too.
#include <sys/resource.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>

// on SunOS 4.x, getrusage is stated in the man pages and exists, but
// is not declared in resource.h. declare it ourselves
#ifdef NO_HAVE_GETRUSAGE
extern "C" {
  int getrusage(int who, struct rusage* ru);
}
#endif

// When modifying the prefix list, we need to lock it just in case
// another thread tries to do the same.
DEAL_II_NAMESPACE_OPEN

namespace
{
  Threads::ThreadMutex log_lock;
  Threads::ThreadMutex write_lock;
}

LogStream deallog;

LogStream::LogStream()
		:
		std_out(&std::cerr), file(0),
		std_depth(10000), file_depth(10000),
		print_utime(false), diff_utime(false),
		last_time (0.), double_threshold(0.), old_cerr(0)
{
  prefixes.push("DEAL:");
  std_out->setf(std::ios::showpoint | std::ios::left);
#ifdef HAVE_TIMES
  reference_time_val = 1./sysconf(_SC_CLK_TCK) * times(&reference_tms);
#endif
}

LogStream::~LogStream()
{
				   // if there was anything left in
				   // the stream that is current to
				   // this thread, make sure we flush
				   // it before it gets lost
  {
    const unsigned int id = Threads::this_thread_id();
    if ((outstreams.find(id) != outstreams.end())
	&&
	(*outstreams[id] != 0)
	&&
	(outstreams[id]->str().length() > 0))
      *this << std::endl;
  }

  if (old_cerr)
    std::cerr.rdbuf(old_cerr);

				   // on some systems, destroying the
				   // outstreams objects of deallog
				   // triggers some sort of memory
				   // corruption, in particular when
				   // we also link with Trilinos;
				   // since this happens at the very
				   // end of the program, we take the
				   // liberty to simply not do it by
				   // putting that object into a
				   // deliberate memory leak and
				   // instead destroying an empty
				   // object
#ifdef DEAL_II_USE_TRILINOS
  if (this == &deallog)
    {
      stream_map_type * dummy = new stream_map_type();
      dummy->swap (outstreams);
      delete dummy;
    }
#endif
}

LogStream &
LogStream::operator<< (std::ostream& (*p) (std::ostream&))
{
				   // do the work that is common to
				   // the operator<< functions
  print (p);

				   // next check whether this is the
				   // <tt>endl</tt> manipulator, and if so
				   // set a flag
  std::ostream & (* const p_endl) (std::ostream&) = &std::endl;
  if (p == p_endl)
    {
      Threads::ThreadMutex::ScopedLock lock(write_lock);
      print_line_head();
      std::ostringstream& stream = get_stream();
      if (prefixes.size() <= std_depth)
	*std_out << stream.str();

      if (file && (prefixes.size() <= file_depth))
	*file << stream.str() << std::flush;

				       // Start a new string
      stream.str("");
    }
  return *this;
}

std::ostringstream&
LogStream::get_stream()
{
//TODO: use a ThreadLocalStorage object here
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  const unsigned int id = Threads::this_thread_id();

  std_cxx1x::shared_ptr<std::ostringstream>& sptr = outstreams[id];
  if (sptr == std_cxx1x::shared_ptr<std::ostringstream>())
    {
      sptr = std_cxx1x::shared_ptr<std::ostringstream> (new std::ostringstream());
      sptr->setf(std::ios::showpoint | std::ios::left);
    }
  return *sptr;
}

void
LogStream::attach(std::ostream& o)
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  file = &o;
  o.setf(std::ios::showpoint | std::ios::left);
  o << dealjobid();
}

void LogStream::detach ()
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  file = 0;
}

void LogStream::log_cerr ()
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  if (old_cerr == 0)
    {
      old_cerr = std::cerr.rdbuf(file->rdbuf());
    } else {
      std::cerr.rdbuf(old_cerr);
      old_cerr = 0;
    }
}

std::ostream&
LogStream::get_console()
{
  return *std_out;
}

std::ostream&
LogStream::get_file_stream()
{
  Assert(file, ExcNoFileStreamGiven());
  return *file;
}

bool
LogStream::has_file() const
{
  return (file != 0);
}

const std::string&
LogStream::get_prefix() const
{
  return prefixes.top();
}

void
LogStream::push (const std::string& text)
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  std::string pre=prefixes.top();
  pre += text;
  pre += std::string(":");
  prefixes.push(pre);
}

void LogStream::pop ()
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  if (prefixes.size() > 1)
    prefixes.pop();
}

unsigned int
LogStream::depth_console (const unsigned n)
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  const unsigned int h = std_depth;
  std_depth = n;
  return h;
}

unsigned int
LogStream::depth_file (const unsigned n)
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  const unsigned int h = file_depth;
  file_depth = n;
  return h;
}

void
LogStream::threshold_double (const double t)
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  double_threshold = t;
}

bool
LogStream::log_execution_time (const bool flag)
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  const bool h = print_utime;
  print_utime = flag;
  return h;
}

bool
LogStream::log_time_differences (const bool flag)
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  const bool h = diff_utime;
  diff_utime = flag;
  return h;
}

bool
LogStream::log_thread_id (const bool flag)
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  const bool h = print_thread_id;
  print_thread_id = flag;
  return h;
}

void
LogStream::print_line_head()
{
  rusage usage;
  double utime = 0.;
  if (print_utime)
    {
      getrusage(RUSAGE_SELF, &usage);
      utime = usage.ru_utime.tv_sec + 1.e-6 * usage.ru_utime.tv_usec;
      if (diff_utime)
	{
	  double diff = utime - last_time;
	  last_time = utime;
	  utime = diff;
	}
    }

/*
 * The following lines were used for debugging a memory leak.
 * They work on Linux, not on Solaris, since the /proc filesystem
 * on Solaris is quite cryptic. For other systems, we don't know.
 *
 * Unfortunately, the information in /proc/pid/stat is updated slowly,
 * therefore, the information is quite unreliable.
 *
 * Furthermore, the constructor of ifstream caused another memory leak.
 *
 * Still, this code might be useful sometimes, so I kept it here.
 * When we have more information about the kernel, this should be
 * incorporated properly. Suggestions are welcome!
 */

#ifdef DEALII_MEMORY_DEBUG
  static const pid_t id = getpid();

  std::ostringstream statname;
  statname << "/proc/" << id << "/stat";

  static long size;
  static string dummy;
  ifstream stat(statname.str());
				   // ignore 22 values
  stat >> dummy >> dummy >> dummy >> dummy >> dummy >> dummy >>
    dummy >> dummy >> dummy >> dummy >> dummy >>
    dummy >> dummy >> dummy >> dummy >> dummy >> dummy >>
    dummy >> dummy >> dummy >> dummy >> dummy >> size;
#endif

  const std::string& head = get_prefix();
  const unsigned int thread = Threads::this_thread_id();

  if (prefixes.size() <= std_depth)
    {
      if (print_utime)
	{
	  int p = std_out->width(5);
	  *std_out << utime << ':';
#ifdef DEALII_MEMORY_DEBUG
	  *std_out << size << ':';
#endif
	  std_out->width(p);
	}
      if (print_thread_id)
	*std_out << '[' << thread << ']';

      *std_out <<  head << ':';
    }

  if (file && (prefixes.size() <= file_depth))
    {
      if (print_utime)
	{
	  int p = file->width(6);
	  *file << utime << ':';
#ifdef DEALII_MEMORY_DEBUG
	  *file << size << ':';
#endif
	  file->width(p);
	}
      if (print_thread_id)
	*file << '[' << thread << ']';

      *file << head << ':';
    }
}

void
LogStream::timestamp ()
{
  struct tms current_tms;
#ifdef HAVE_TIMES
  const clock_t tick = sysconf(_SC_CLK_TCK);
  const double time = 1./tick * times(&current_tms);
#else
  const double time = 0.;
  const unsigned int tick = 100;
#endif
  (*this) << "Wall: " << time - reference_time_val
	  << " User: " << 1./tick * (current_tms.tms_utime - reference_tms.tms_utime)
	  << " System: " << 1./tick * (current_tms.tms_stime - reference_tms.tms_stime)
	  << " Child-User: " << 1./tick * (current_tms.tms_cutime - reference_tms.tms_cutime)
	  << " Child-System: " << 1./tick * (current_tms.tms_cstime - reference_tms.tms_cstime)
	  << std::endl;
}

std::size_t
LogStream::memory_consumption () const
{
  std::size_t mem = sizeof(*this);
				   // to determine size of stack
				   // elements, we have to copy the
				   // stack since we can't access
				   // elements from further below
  std::stack<std::string> tmp = prefixes;
  while (tmp.empty() == false)
    {
      mem += MemoryConsumption::memory_consumption (tmp.top());
      tmp.pop ();
    }

  return mem;
}

DEAL_II_NAMESPACE_CLOSE
<commit_msg>Simplify code slightly.<commit_after>//---------------------------------------------------------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2011 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//---------------------------------------------------------------------------

#include <deal.II/base/logstream.h>
#include <deal.II/base/job_identifier.h>
#include <deal.II/base/memory_consumption.h>
#include <deal.II/base/thread_management.h>

// include sys/resource.h for rusage(). Mac OS X needs sys/time.h then
// as well (strange), so include that, too.
#include <sys/resource.h>
#include <sys/types.h>
#include <unistd.h>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>

// on SunOS 4.x, getrusage is stated in the man pages and exists, but
// is not declared in resource.h. declare it ourselves
#ifdef NO_HAVE_GETRUSAGE
extern "C" {
  int getrusage(int who, struct rusage* ru);
}
#endif

// When modifying the prefix list, we need to lock it just in case
// another thread tries to do the same.
DEAL_II_NAMESPACE_OPEN

namespace
{
  Threads::ThreadMutex log_lock;
  Threads::ThreadMutex write_lock;
}

LogStream deallog;

LogStream::LogStream()
		:
		std_out(&std::cerr), file(0),
		std_depth(10000), file_depth(10000),
		print_utime(false), diff_utime(false),
		last_time (0.), double_threshold(0.), old_cerr(0)
{
  prefixes.push("DEAL:");
  std_out->setf(std::ios::showpoint | std::ios::left);
#ifdef HAVE_TIMES
  reference_time_val = 1./sysconf(_SC_CLK_TCK) * times(&reference_tms);
#endif
}

LogStream::~LogStream()
{
				   // if there was anything left in
				   // the stream that is current to
				   // this thread, make sure we flush
				   // it before it gets lost
  {
    const unsigned int id = Threads::this_thread_id();
    if ((outstreams.find(id) != outstreams.end())
	&&
	(*outstreams[id] != 0)
	&&
	(outstreams[id]->str().length() > 0))
      *this << std::endl;
  }

  if (old_cerr)
    std::cerr.rdbuf(old_cerr);

				   // on some systems, destroying the
				   // outstreams objects of deallog
				   // triggers some sort of memory
				   // corruption, in particular when
				   // we also link with Trilinos;
				   // since this happens at the very
				   // end of the program, we take the
				   // liberty to simply not do it by
				   // putting that object into a
				   // deliberate memory leak and
				   // instead destroying an empty
				   // object
#ifdef DEAL_II_USE_TRILINOS
  if (this == &deallog)
    {
      stream_map_type * dummy = new stream_map_type();
      dummy->swap (outstreams);
      delete dummy;
    }
#endif
}

LogStream &
LogStream::operator<< (std::ostream& (*p) (std::ostream&))
{
				   // do the work that is common to
				   // the operator<< functions
  print (p);

				   // next check whether this is the
				   // <tt>endl</tt> manipulator, and if so
				   // set a flag
  std::ostream & (* const p_endl) (std::ostream&) = &std::endl;
  if (p == p_endl)
    {
      Threads::ThreadMutex::ScopedLock lock(write_lock);
      print_line_head();
      std::ostringstream& stream = get_stream();
      if (prefixes.size() <= std_depth)
	*std_out << stream.str();

      if (file && (prefixes.size() <= file_depth))
	*file << stream.str() << std::flush;

				       // Start a new string
      stream.str("");
    }
  return *this;
}

std::ostringstream&
LogStream::get_stream()
{
//TODO: use a ThreadLocalStorage object here
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  const unsigned int id = Threads::this_thread_id();

				   // if necessary allocate a stream object
  if (outstreams.find (id) == outstreams.end())
    {
      outstreams[id].reset (new std::ostringstream());
      outstreams[id]->setf(std::ios::showpoint | std::ios::left);
    }
  return *outstreams[id];
}

void
LogStream::attach(std::ostream& o)
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  file = &o;
  o.setf(std::ios::showpoint | std::ios::left);
  o << dealjobid();
}

void LogStream::detach ()
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  file = 0;
}

void LogStream::log_cerr ()
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  if (old_cerr == 0)
    {
      old_cerr = std::cerr.rdbuf(file->rdbuf());
    } else {
      std::cerr.rdbuf(old_cerr);
      old_cerr = 0;
    }
}

std::ostream&
LogStream::get_console()
{
  return *std_out;
}

std::ostream&
LogStream::get_file_stream()
{
  Assert(file, ExcNoFileStreamGiven());
  return *file;
}

bool
LogStream::has_file() const
{
  return (file != 0);
}

const std::string&
LogStream::get_prefix() const
{
  return prefixes.top();
}

void
LogStream::push (const std::string& text)
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  std::string pre=prefixes.top();
  pre += text;
  pre += std::string(":");
  prefixes.push(pre);
}

void LogStream::pop ()
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  if (prefixes.size() > 1)
    prefixes.pop();
}

unsigned int
LogStream::depth_console (const unsigned n)
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  const unsigned int h = std_depth;
  std_depth = n;
  return h;
}

unsigned int
LogStream::depth_file (const unsigned n)
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  const unsigned int h = file_depth;
  file_depth = n;
  return h;
}

void
LogStream::threshold_double (const double t)
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  double_threshold = t;
}

bool
LogStream::log_execution_time (const bool flag)
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  const bool h = print_utime;
  print_utime = flag;
  return h;
}

bool
LogStream::log_time_differences (const bool flag)
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  const bool h = diff_utime;
  diff_utime = flag;
  return h;
}

bool
LogStream::log_thread_id (const bool flag)
{
  Threads::ThreadMutex::ScopedLock lock(log_lock);
  const bool h = print_thread_id;
  print_thread_id = flag;
  return h;
}

void
LogStream::print_line_head()
{
  rusage usage;
  double utime = 0.;
  if (print_utime)
    {
      getrusage(RUSAGE_SELF, &usage);
      utime = usage.ru_utime.tv_sec + 1.e-6 * usage.ru_utime.tv_usec;
      if (diff_utime)
	{
	  double diff = utime - last_time;
	  last_time = utime;
	  utime = diff;
	}
    }

/*
 * The following lines were used for debugging a memory leak.
 * They work on Linux, not on Solaris, since the /proc filesystem
 * on Solaris is quite cryptic. For other systems, we don't know.
 *
 * Unfortunately, the information in /proc/pid/stat is updated slowly,
 * therefore, the information is quite unreliable.
 *
 * Furthermore, the constructor of ifstream caused another memory leak.
 *
 * Still, this code might be useful sometimes, so I kept it here.
 * When we have more information about the kernel, this should be
 * incorporated properly. Suggestions are welcome!
 */

#ifdef DEALII_MEMORY_DEBUG
  static const pid_t id = getpid();

  std::ostringstream statname;
  statname << "/proc/" << id << "/stat";

  static long size;
  static string dummy;
  ifstream stat(statname.str());
				   // ignore 22 values
  stat >> dummy >> dummy >> dummy >> dummy >> dummy >> dummy >>
    dummy >> dummy >> dummy >> dummy >> dummy >>
    dummy >> dummy >> dummy >> dummy >> dummy >> dummy >>
    dummy >> dummy >> dummy >> dummy >> dummy >> size;
#endif

  const std::string& head = get_prefix();
  const unsigned int thread = Threads::this_thread_id();

  if (prefixes.size() <= std_depth)
    {
      if (print_utime)
	{
	  int p = std_out->width(5);
	  *std_out << utime << ':';
#ifdef DEALII_MEMORY_DEBUG
	  *std_out << size << ':';
#endif
	  std_out->width(p);
	}
      if (print_thread_id)
	*std_out << '[' << thread << ']';

      *std_out <<  head << ':';
    }

  if (file && (prefixes.size() <= file_depth))
    {
      if (print_utime)
	{
	  int p = file->width(6);
	  *file << utime << ':';
#ifdef DEALII_MEMORY_DEBUG
	  *file << size << ':';
#endif
	  file->width(p);
	}
      if (print_thread_id)
	*file << '[' << thread << ']';

      *file << head << ':';
    }
}

void
LogStream::timestamp ()
{
  struct tms current_tms;
#ifdef HAVE_TIMES
  const clock_t tick = sysconf(_SC_CLK_TCK);
  const double time = 1./tick * times(&current_tms);
#else
  const double time = 0.;
  const unsigned int tick = 100;
#endif
  (*this) << "Wall: " << time - reference_time_val
	  << " User: " << 1./tick * (current_tms.tms_utime - reference_tms.tms_utime)
	  << " System: " << 1./tick * (current_tms.tms_stime - reference_tms.tms_stime)
	  << " Child-User: " << 1./tick * (current_tms.tms_cutime - reference_tms.tms_cutime)
	  << " Child-System: " << 1./tick * (current_tms.tms_cstime - reference_tms.tms_cstime)
	  << std::endl;
}

std::size_t
LogStream::memory_consumption () const
{
  std::size_t mem = sizeof(*this);
				   // to determine size of stack
				   // elements, we have to copy the
				   // stack since we can't access
				   // elements from further below
  std::stack<std::string> tmp = prefixes;
  while (tmp.empty() == false)
    {
      mem += MemoryConsumption::memory_consumption (tmp.top());
      tmp.pop ();
    }

  return mem;
}

DEAL_II_NAMESPACE_CLOSE
<|endoftext|>


<commit_before>//---------------------------------------------------------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2011, 2012 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//---------------------------------------------------------------------------

#include <deal.II/base/logstream.h>
#include <deal.II/base/job_identifier.h>
#include <deal.II/base/memory_consumption.h>
#include <deal.II/base/thread_management.h>

#ifdef HAVE_SYS_RESOURCE_H
#  include <sys/resource.h>
#endif

#ifdef HAVE_UNISTD_H
#  include <unistd.h>
#endif

#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>

DEAL_II_NAMESPACE_OPEN

namespace
{
  Threads::Mutex log_lock;
  Threads::Mutex write_lock;
}

// The standard log object of deal.II:
LogStream deallog;

LogStream::LogStream()
  :
  std_out(&std::cerr),
  file(0),
  std_depth(10000),
  file_depth(10000),
  print_utime(false),
  diff_utime(false),
  last_time (0.),
  double_threshold(0.),
  float_threshold(0.),
  offset(0),
  old_cerr(0),
  at_newline(true)
{
  get_prefixes().push("DEAL:");

#if defined(HAVE_UNISTD_H) && defined(HAVE_TIMES)
  reference_time_val = 1./sysconf(_SC_CLK_TCK) * times(&reference_tms);
#endif

}

LogStream::~LogStream()
{
  // if there was anything left in the stream that is current to this
  // thread, make sure we flush it before it gets lost
  {
    if (get_stream().str().length() > 0)
      {
        // except the situation is not quite that simple. if this object is
        // the 'deallog' object, then it is destroyed upon exit of the
        // program. since it's defined in a shared library that depends on
        // libstdc++.so, destruction happens before destruction of
        // std::cout/cerr, but after all file variables defined in user
        // programs have been destroyed. in other words, if we get here and
        // the object being destroyed is 'deallog' and if 'deallog' is
        // associated with a file stream, then we're in trouble: we'll try
        // to write to a file that doesn't exist any more, and we're likely
        // going to crash (this is tested by base/log_crash_01). rather
        // than letting it come to this, print a message to the screen
        // (note that we can't issue an assertion here either since Assert
        // may want to write to 'deallog' itself, and AssertThrow will
        // throw an exception that can't be caught)
        if ((this == &deallog) && file)
          std::cerr << ("You still have content that was written to 'deallog' "
                        "but not flushed to the screen or a file while the "
                        "program is being terminated. This would lead to a "
                        "segmentation fault. Make sure you flush the "
                        "content of the 'deallog' object using 'std::endl' "
                        "before the end of the program.")
                    << std::endl;
        else
          *this << std::endl;
      }
  }

  if (old_cerr)
    std::cerr.rdbuf(old_cerr);
}

void
LogStream::test_mode(bool on)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  if (on)
    {
      double_threshold = 1.e-10;
      float_threshold = 1.e-7;
      offset = 1.e-7;
    }
  else
    {
      double_threshold = 0.;
      float_threshold = 0.;
      offset = 0.;
    }
}

LogStream &
LogStream::operator<< (std::ostream& (*p) (std::ostream &))
{
  std::ostringstream &stream = get_stream();

  // Print to the internal stringstream:
  stream << p;

  // Next check whether this is the <tt>flush</tt> or <tt>endl</tt>
  // manipulator, and if so print out the message.
  std::ostream & (* const p_flush) (std::ostream &) = &std::flush;
  std::ostream & (* const p_endl) (std::ostream &) = &std::endl;
  if (p == p_flush || p == p_endl)
    {
      Threads::Mutex::ScopedLock lock(write_lock);

      // Print the line head in case of a newline:
      if (at_newline)
        print_line_head();

      if(p == p_flush)
        at_newline = false;

      if(p == p_endl)
        at_newline = true;

      if (get_prefixes().size() <= std_depth)
        *std_out << stream.str();

      if (file && (get_prefixes().size() <= file_depth))
        *file << stream.str() << std::flush;

      // Start a new string
      stream.str("");
    }

  return *this;
}

void
LogStream::attach(std::ostream &o)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  file = &o;
  o.setf(std::ios::showpoint | std::ios::left);
  o << dealjobid();
}

void LogStream::detach ()
{
  Threads::Mutex::ScopedLock lock(log_lock);
  file = 0;
}

void LogStream::log_cerr ()
{
  Threads::Mutex::ScopedLock lock(log_lock);
  if (old_cerr == 0)
    {
      old_cerr = std::cerr.rdbuf(file->rdbuf());
    }
  else
    {
      std::cerr.rdbuf(old_cerr);
      old_cerr = 0;
    }
}

std::ostream &
LogStream::get_console()
{
  return *std_out;
}

std::ostream &
LogStream::get_file_stream()
{
  Assert(file, ExcNoFileStreamGiven());
  return *file;
}

bool
LogStream::has_file() const
{
  return (file != 0);
}

const std::string &
LogStream::get_prefix() const
{
  return get_prefixes().top();
}

void
LogStream::push (const std::string &text)
{
  std::string pre=get_prefixes().top();
  pre += text;
  pre += std::string(":");
  get_prefixes().push(pre);
}

void LogStream::pop ()
{
  if (get_prefixes().size() > 1)
    get_prefixes().pop();
}

unsigned int
LogStream::depth_console (const unsigned int n)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  const unsigned int h = std_depth;
  std_depth = n;
  return h;
}

unsigned int
LogStream::depth_file (const unsigned int n)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  const unsigned int h = file_depth;
  file_depth = n;
  return h;
}

void
LogStream::threshold_double (const double t)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  double_threshold = t;
}

void
LogStream::threshold_float (const float t)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  float_threshold = t;
}

bool
LogStream::log_execution_time (const bool flag)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  const bool h = print_utime;
  print_utime = flag;
  return h;
}

bool
LogStream::log_time_differences (const bool flag)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  const bool h = diff_utime;
  diff_utime = flag;
  return h;
}

bool
LogStream::log_thread_id (const bool flag)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  const bool h = print_thread_id;
  print_thread_id = flag;
  return h;
}

std::stack<std::string> &
LogStream::get_prefixes() const
{
#ifdef DEAL_II_WITH_THREADS
  bool exists = false;
  std::stack<std::string> &local_prefixes = prefixes.get(exists);

  // If this is a new locally stored stack, copy the "blessed" prefixes
  // from the initial thread that created logstream.
  if(! exists)
    {
      const tbb::enumerable_thread_specific<std::stack<std::string> > &impl
        = prefixes.get_implementation();

      // The thread that created this LogStream object should be the first
      // in tbb's enumerable_thread_specific containter.
      const tbb::enumerable_thread_specific<std::stack<std::string> >::const_iterator first_elem
        = impl.begin();

      if (first_elem != impl.end())
        {
          local_prefixes = *first_elem;
        }
    }

  return local_prefixes;

#else
  return prefixes.get();
#endif
}

void
LogStream::print_line_head()
{
#ifdef HAVE_SYS_RESOURCE_H
  rusage usage;
  double utime = 0.;
  if (print_utime)
    {
      getrusage(RUSAGE_SELF, &usage);
      utime = usage.ru_utime.tv_sec + 1.e-6 * usage.ru_utime.tv_usec;
      if (diff_utime)
        {
          double diff = utime - last_time;
          last_time = utime;
          utime = diff;
        }
    }
#else
//TODO[BG]: Do something useful here
  double utime = 0.;
#endif

  /*
   * The following lines were used for debugging a memory leak.
   * They work on Linux, not on Solaris, since the /proc filesystem
   * on Solaris is quite cryptic. For other systems, we don't know.
   *
   * Unfortunately, the information in /proc/pid/stat is updated slowly,
   * therefore, the information is quite unreliable.
   *
   * Furthermore, the constructor of ifstream caused another memory leak.
   *
   * Still, this code might be useful sometimes, so I kept it here.
   * When we have more information about the kernel, this should be
   * incorporated properly. Suggestions are welcome!
   */

#ifdef DEALII_MEMORY_DEBUG
  static const pid_t id = getpid();

  std::ostringstream statname;
  statname << "/proc/" << id << "/stat";

  static long size;
  static string dummy;
  ifstream stat(statname.str());
  // ignore 22 values
  stat >> dummy >> dummy >> dummy >> dummy >> dummy >> dummy >>
       dummy >> dummy >> dummy >> dummy >> dummy >>
       dummy >> dummy >> dummy >> dummy >> dummy >> dummy >>
       dummy >> dummy >> dummy >> dummy >> dummy >> size;
#endif

  const std::string &head = get_prefix();
  const unsigned int thread = Threads::this_thread_id();

  if (get_prefixes().size() <= std_depth)
    {
      if (print_utime)
        {
          int p = std_out->width(5);
          *std_out << utime << ':';
#ifdef DEALII_MEMORY_DEBUG
          *std_out << size << ':';
#endif
          std_out->width(p);
        }
      if (print_thread_id)
        *std_out << '[' << thread << ']';

      *std_out <<  head << ':';
    }

  if (file && (get_prefixes().size() <= file_depth))
    {
      if (print_utime)
        {
          int p = file->width(6);
          *file << utime << ':';
#ifdef DEALII_MEMORY_DEBUG
          *file << size << ':';
#endif
          file->width(p);
        }
      if (print_thread_id)
        *file << '[' << thread << ']';

      *file << head << ':';
    }
}

void
LogStream::timestamp ()
{
  struct tms current_tms;
#if defined(HAVE_UNISTD_H) && defined(HAVE_TIMES)
  const clock_t tick = sysconf(_SC_CLK_TCK);
  const double time = 1./tick * times(&current_tms);
#else
  const double time = 0.;
  const unsigned int tick = 100;
#endif
  (*this) << "Wall: " << time - reference_time_val
          << " User: " << 1./tick * (current_tms.tms_utime - reference_tms.tms_utime)
          << " System: " << 1./tick * (current_tms.tms_stime - reference_tms.tms_stime)
          << " Child-User: " << 1./tick * (current_tms.tms_cutime - reference_tms.tms_cutime)
          << " Child-System: " << 1./tick * (current_tms.tms_cstime - reference_tms.tms_cstime)
          << std::endl;
}

std::size_t
LogStream::memory_consumption () const
{
  // TODO
  Assert(false, ExcNotImplemented());

  std::size_t mem = sizeof(*this);
  // to determine size of stack
  // elements, we have to copy the
  // stack since we can't access
  // elements from further below
//   std::stack<std::string> tmp = prefixes;
//   while (tmp.empty() == false)
//     {
//       mem += MemoryConsumption::memory_consumption (tmp.top());
//       tmp.pop ();
//     }

  return mem;
}

DEAL_II_NAMESPACE_CLOSE
<commit_msg>Commit the second part of Fahad's patch that was accidentally forgotten :-(<commit_after>//---------------------------------------------------------------------------
//    $Id$
//    Version: $Name$
//
//    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2008, 2009, 2010, 2011, 2012 by the deal.II authors
//
//    This file is subject to QPL and may not be  distributed
//    without copyright and license information. Please refer
//    to the file deal.II/doc/license.html for the  text  and
//    further information on this license.
//
//---------------------------------------------------------------------------

#include <deal.II/base/logstream.h>
#include <deal.II/base/job_identifier.h>
#include <deal.II/base/memory_consumption.h>
#include <deal.II/base/thread_management.h>

#ifdef HAVE_SYS_RESOURCE_H
#  include <sys/resource.h>
#endif

#ifdef HAVE_UNISTD_H
#  include <unistd.h>
#endif

#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>

DEAL_II_NAMESPACE_OPEN

namespace
{
  Threads::Mutex log_lock;
  Threads::Mutex write_lock;
}

// The standard log object of deal.II:
LogStream deallog;

LogStream::LogStream()
  :
  std_out(&std::cerr),
  file(0),
  std_depth(10000),
  file_depth(10000),
  print_utime(false),
  diff_utime(false),
  last_time (0.),
  double_threshold(0.),
  float_threshold(0.),
  offset(0),
  old_cerr(0),
  at_newline(true),
  stream_flags(std::ios::showpoint | std::ios::left),
  stream_width(std::cout.width()),
  stream_precision(std::cout.precision())
{
  get_prefixes().push("DEAL:");

#if defined(HAVE_UNISTD_H) && defined(HAVE_TIMES)
  reference_time_val = 1./sysconf(_SC_CLK_TCK) * times(&reference_tms);
#endif

}

LogStream::~LogStream()
{
  // if there was anything left in the stream that is current to this
  // thread, make sure we flush it before it gets lost
  {
    if (get_stream().str().length() > 0)
      {
        // except the situation is not quite that simple. if this object is
        // the 'deallog' object, then it is destroyed upon exit of the
        // program. since it's defined in a shared library that depends on
        // libstdc++.so, destruction happens before destruction of
        // std::cout/cerr, but after all file variables defined in user
        // programs have been destroyed. in other words, if we get here and
        // the object being destroyed is 'deallog' and if 'deallog' is
        // associated with a file stream, then we're in trouble: we'll try
        // to write to a file that doesn't exist any more, and we're likely
        // going to crash (this is tested by base/log_crash_01). rather
        // than letting it come to this, print a message to the screen
        // (note that we can't issue an assertion here either since Assert
        // may want to write to 'deallog' itself, and AssertThrow will
        // throw an exception that can't be caught)
        if ((this == &deallog) && file)
          std::cerr << ("You still have content that was written to 'deallog' "
                        "but not flushed to the screen or a file while the "
                        "program is being terminated. This would lead to a "
                        "segmentation fault. Make sure you flush the "
                        "content of the 'deallog' object using 'std::endl' "
                        "before the end of the program.")
                    << std::endl;
        else
          *this << std::endl;
      }
  }

  if (old_cerr)
    std::cerr.rdbuf(old_cerr);
}

void
LogStream::test_mode(bool on)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  if (on)
    {
      double_threshold = 1.e-10;
      float_threshold = 1.e-7;
      offset = 1.e-7;
    }
  else
    {
      double_threshold = 0.;
      float_threshold = 0.;
      offset = 0.;
    }
}

LogStream &
LogStream::operator<< (std::ostream& (*p) (std::ostream &))
{

  std::ostringstream &stream = get_stream();
  // save the state of out stream
  std::ios::fmtflags old_flags = stream.flags(stream_flags);
  unsigned int old_precision = stream.precision (stream_precision);
  unsigned int old_width = stream.width (stream_width);

  // Print to the internal stringstream:
  stream << p;

  // Next check whether this is the <tt>flush</tt> or <tt>endl</tt>
  // manipulator, and if so print out the message.
  std::ostream & (* const p_flush) (std::ostream &) = &std::flush;
  std::ostream & (* const p_endl) (std::ostream &) = &std::endl;
  if (p == p_flush || p == p_endl)
    {
      Threads::Mutex::ScopedLock lock(write_lock);

      // Print the line head in case of a newline:
      if (at_newline)
        print_line_head();

      if(p == p_flush)
        at_newline = false;

      if(p == p_endl)
        at_newline = true;

      if (get_prefixes().size() <= std_depth)
        *std_out << stream.str();

      if (file && (get_prefixes().size() <= file_depth))
        *file << stream.str() << std::flush;

      // Start a new string
      stream.str("");
    }

  // reset output format
  stream.flags (old_flags);
  stream.precision(old_precision);
  stream.width(old_width);

  return *this;
}

void
LogStream::attach(std::ostream &o)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  file = &o;
  o.setf(std::ios::showpoint | std::ios::left);
  o << dealjobid();
}

void LogStream::detach ()
{
  Threads::Mutex::ScopedLock lock(log_lock);
  file = 0;
}

void LogStream::log_cerr ()
{
  Threads::Mutex::ScopedLock lock(log_lock);
  if (old_cerr == 0)
    {
      old_cerr = std::cerr.rdbuf(file->rdbuf());
    }
  else
    {
      std::cerr.rdbuf(old_cerr);
      old_cerr = 0;
    }
}

std::ostream &
LogStream::get_console()
{
  return *std_out;
}

std::ostream &
LogStream::get_file_stream()
{
  Assert(file, ExcNoFileStreamGiven());
  return *file;
}

bool
LogStream::has_file() const
{
  return (file != 0);
}

const std::string &
LogStream::get_prefix() const
{
  return get_prefixes().top();
}

void
LogStream::push (const std::string &text)
{
  std::string pre=get_prefixes().top();
  pre += text;
  pre += std::string(":");
  get_prefixes().push(pre);
}

void LogStream::pop ()
{
  if (get_prefixes().size() > 1)
    get_prefixes().pop();
}

std::ios::fmtflags
LogStream::flags(const std::ios::fmtflags f)
{
  std::ios::fmtflags tmp = stream_flags;
  stream_flags = f;
  return tmp;
}

std::streamsize
LogStream::precision (const std::streamsize prec)
{
  std::streamsize tmp = stream_precision;
  stream_precision = prec;
  return tmp;
}

std::streamsize
LogStream::width (const std::streamsize wide)
{
  std::streamsize tmp = stream_width;
  stream_width = wide;
  return tmp;
}

unsigned int
LogStream::depth_console (const unsigned int n)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  const unsigned int h = std_depth;
  std_depth = n;
  return h;
}

unsigned int
LogStream::depth_file (const unsigned int n)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  const unsigned int h = file_depth;
  file_depth = n;
  return h;
}

void
LogStream::threshold_double (const double t)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  double_threshold = t;
}

void
LogStream::threshold_float (const float t)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  float_threshold = t;
}

bool
LogStream::log_execution_time (const bool flag)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  const bool h = print_utime;
  print_utime = flag;
  return h;
}

bool
LogStream::log_time_differences (const bool flag)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  const bool h = diff_utime;
  diff_utime = flag;
  return h;
}

bool
LogStream::log_thread_id (const bool flag)
{
  Threads::Mutex::ScopedLock lock(log_lock);
  const bool h = print_thread_id;
  print_thread_id = flag;
  return h;
}

std::stack<std::string> &
LogStream::get_prefixes() const
{
#ifdef DEAL_II_WITH_THREADS
  bool exists = false;
  std::stack<std::string> &local_prefixes = prefixes.get(exists);

  // If this is a new locally stored stack, copy the "blessed" prefixes
  // from the initial thread that created logstream.
  if(! exists)
    {
      const tbb::enumerable_thread_specific<std::stack<std::string> > &impl
        = prefixes.get_implementation();

      // The thread that created this LogStream object should be the first
      // in tbb's enumerable_thread_specific containter.
      const tbb::enumerable_thread_specific<std::stack<std::string> >::const_iterator first_elem
        = impl.begin();

      if (first_elem != impl.end())
        {
          local_prefixes = *first_elem;
        }
    }

  return local_prefixes;

#else
  return prefixes.get();
#endif
}

void
LogStream::print_line_head()
{
#ifdef HAVE_SYS_RESOURCE_H
  rusage usage;
  double utime = 0.;
  if (print_utime)
    {
      getrusage(RUSAGE_SELF, &usage);
      utime = usage.ru_utime.tv_sec + 1.e-6 * usage.ru_utime.tv_usec;
      if (diff_utime)
        {
          double diff = utime - last_time;
          last_time = utime;
          utime = diff;
        }
    }
#else
//TODO[BG]: Do something useful here
  double utime = 0.;
#endif

  /*
   * The following lines were used for debugging a memory leak.
   * They work on Linux, not on Solaris, since the /proc filesystem
   * on Solaris is quite cryptic. For other systems, we don't know.
   *
   * Unfortunately, the information in /proc/pid/stat is updated slowly,
   * therefore, the information is quite unreliable.
   *
   * Furthermore, the constructor of ifstream caused another memory leak.
   *
   * Still, this code might be useful sometimes, so I kept it here.
   * When we have more information about the kernel, this should be
   * incorporated properly. Suggestions are welcome!
   */

#ifdef DEALII_MEMORY_DEBUG
  static const pid_t id = getpid();

  std::ostringstream statname;
  statname << "/proc/" << id << "/stat";

  static long size;
  static string dummy;
  ifstream stat(statname.str());
  // ignore 22 values
  stat >> dummy >> dummy >> dummy >> dummy >> dummy >> dummy >>
       dummy >> dummy >> dummy >> dummy >> dummy >>
       dummy >> dummy >> dummy >> dummy >> dummy >> dummy >>
       dummy >> dummy >> dummy >> dummy >> dummy >> size;
#endif

  const std::string &head = get_prefix();
  const unsigned int thread = Threads::this_thread_id();

  if (get_prefixes().size() <= std_depth)
    {
      if (print_utime)
        {
          int p = std_out->width(5);
          *std_out << utime << ':';
#ifdef DEALII_MEMORY_DEBUG
          *std_out << size << ':';
#endif
          std_out->width(p);
        }
      if (print_thread_id)
        *std_out << '[' << thread << ']';

      *std_out <<  head << ':';
    }

  if (file && (get_prefixes().size() <= file_depth))
    {
      if (print_utime)
        {
          int p = file->width(6);
          *file << utime << ':';
#ifdef DEALII_MEMORY_DEBUG
          *file << size << ':';
#endif
          file->width(p);
        }
      if (print_thread_id)
        *file << '[' << thread << ']';

      *file << head << ':';
    }
}

void
LogStream::timestamp ()
{
  struct tms current_tms;
#if defined(HAVE_UNISTD_H) && defined(HAVE_TIMES)
  const clock_t tick = sysconf(_SC_CLK_TCK);
  const double time = 1./tick * times(&current_tms);
#else
  const double time = 0.;
  const unsigned int tick = 100;
#endif
  (*this) << "Wall: " << time - reference_time_val
          << " User: " << 1./tick * (current_tms.tms_utime - reference_tms.tms_utime)
          << " System: " << 1./tick * (current_tms.tms_stime - reference_tms.tms_stime)
          << " Child-User: " << 1./tick * (current_tms.tms_cutime - reference_tms.tms_cutime)
          << " Child-System: " << 1./tick * (current_tms.tms_cstime - reference_tms.tms_cstime)
          << std::endl;
}

std::size_t
LogStream::memory_consumption () const
{
  // TODO
  Assert(false, ExcNotImplemented());

  std::size_t mem = sizeof(*this);
  // to determine size of stack
  // elements, we have to copy the
  // stack since we can't access
  // elements from further below
//   std::stack<std::string> tmp = prefixes;
//   while (tmp.empty() == false)
//     {
//       mem += MemoryConsumption::memory_consumption (tmp.top());
//       tmp.pop ();
//     }

  return mem;
}

DEAL_II_NAMESPACE_CLOSE
<|endoftext|>