<commit_before>// https://github.com/meyburgh/forirony
#include "Leap.h" // the leap sdk header
#include <string.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

namespace
{
	void LeapVideo()
	{
		Leap::Controller controller;
		controller.setPolicy(Leap::Controller::POLICY_IMAGES);

		cv::String const windowName[] = { "0", "1" };

		while (controller.isConnected())
		{
			Leap::Frame const frame = controller.frame(0);

			Leap::ImageList const & imageList = frame.images();
			uint8_t const imageCount = imageList.count();

			for (uint8_t imageIndex = 0; imageIndex < imageCount; ++imageIndex)
			{
				Leap::Image const & image = imageList[imageIndex];
				//Leap::Vector v = image.rectify() // you can rectify the video images this way, but it's slow, best to use a shader

				//image.data() points at width * height * bytes per pixel, 8-bit intensity values
				uint32_t const rows = image.height();
				uint32_t const columns = image.width();
				cv::Mat const mat(rows, columns, CV_8UC1);
				uint32_t const imageSize = sizeof(uint8_t) * rows * columns * image.bytesPerPixel();
				memcpy(mat.data, image.data(), imageSize);

				cv::imshow(windowName[imageIndex], mat);
				cv::waitKey(16); // 60 fps poor man's frame limiter
			}
		}
	}
}

int main(int const argc, char const * const * const argv)
{
	LeapVideo();

	return 0;
}
<commit_msg>controller isconnected is unreliable initially, so just keep trying<commit_after>// https://github.com/meyburgh/forirony
#include "Leap.h" // the leap sdk header
#include <string.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

namespace
{
	void LeapVideo()
	{
		Leap::Controller controller;
		controller.setPolicy(Leap::Controller::POLICY_IMAGES);

		cv::String const windowName[] = { "0", "1" };

		for (;;)
		{
			Leap::Frame const frame = controller.frame(0);

			Leap::ImageList const & imageList = frame.images();
			uint8_t const imageCount = imageList.count();

			for (uint8_t imageIndex = 0; imageIndex < imageCount; ++imageIndex)
			{
				Leap::Image const & image = imageList[imageIndex];
				//Leap::Vector v = image.rectify() // you can rectify the video images this way, but it's slow, best to use a shader

				//image.data() points at width * height * bytes per pixel, 8-bit intensity values
				uint32_t const rows = image.height();
				uint32_t const columns = image.width();
				cv::Mat const mat(rows, columns, CV_8UC1);
				uint32_t const imageSize = sizeof(uint8_t) * rows * columns * image.bytesPerPixel();
				memcpy(mat.data, image.data(), imageSize);

				cv::imshow(windowName[imageIndex], mat);
				cv::waitKey(16); // 60 fps poor man's frame limiter
			}
		}
	}
}

int main(int const argc, char const * const * const argv)
{
	LeapVideo();

	return 0;
}
<|endoftext|>


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

#include "src/trace_processor/importers/common/clock_tracker.h"

#include <inttypes.h>

#include <algorithm>
#include <atomic>
#include <queue>

#include "perfetto/base/logging.h"
#include "perfetto/ext/base/hash.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/types/trace_processor_context.h"

#include "protos/perfetto/common/builtin_clock.pbzero.h"
#include "protos/perfetto/trace/clock_snapshot.pbzero.h"

namespace perfetto {
namespace trace_processor {

using Clock = protos::pbzero::ClockSnapshot::Clock;

ClockTracker::ClockTracker(TraceProcessorContext* ctx)
    : context_(ctx),
      trace_time_clock_id_(protos::pbzero::BUILTIN_CLOCK_BOOTTIME) {}

ClockTracker::~ClockTracker() = default;

void ClockTracker::AddSnapshot(const std::vector<ClockValue>& clocks) {
  const auto snapshot_id = cur_snapshot_id_++;

  // Clear the cache
  cache_.fill({});

  // Compute the fingerprint of the snapshot by hashing all clock ids. This is
  // used by the clock pathfinding logic.
  base::Hash hasher;
  for (const auto& clock : clocks)
    hasher.Update(clock.clock_id);
  const auto snapshot_hash = static_cast<SnapshotHash>(hasher.digest());

  // Add a new entry in each clock's snapshot vector.
  for (const auto& clock : clocks) {
    ClockId clock_id = clock.clock_id;
    ClockDomain& domain = clocks_[clock_id];
    if (domain.snapshots.empty()) {
      if (clock.is_incremental && !ClockIsSeqScoped(clock_id)) {
        PERFETTO_ELOG("Clock sync error: the global clock with id=%" PRIu64
                      " cannot use incremental encoding; this is only "
                      "supported for sequence-scoped clocks.",
                      clock_id);
        context_->storage->IncrementStats(stats::invalid_clock_snapshots);
        return;
      }
      domain.unit_multiplier_ns = clock.unit_multiplier_ns;
      domain.is_incremental = clock.is_incremental;
    } else if (PERFETTO_UNLIKELY(
                   domain.unit_multiplier_ns != clock.unit_multiplier_ns ||
                   domain.is_incremental != clock.is_incremental)) {
      PERFETTO_ELOG("Clock sync error: the clock domain with id=%" PRIu64
                    " (unit=%" PRIu64
                    ", incremental=%d), was previously registered with "
                    "different properties (unit=%" PRIu64 ", incremental=%d).",
                    clock_id, clock.unit_multiplier_ns, clock.is_incremental,
                    domain.unit_multiplier_ns, domain.is_incremental);
      context_->storage->IncrementStats(stats::invalid_clock_snapshots);
      return;
    }
    const int64_t timestamp_ns =
        clock.absolute_timestamp * domain.unit_multiplier_ns;
    domain.last_timestamp_ns = timestamp_ns;

    ClockSnapshots& vect = domain.snapshots[snapshot_hash];
    if (!vect.snapshot_ids.empty() &&
        PERFETTO_UNLIKELY(vect.snapshot_ids.back() == snapshot_id)) {
      PERFETTO_ELOG("Clock sync error: duplicate clock domain with id=%" PRIu64
                    " at snapshot %" PRIu32 ".",
                    clock_id, snapshot_id);
      context_->storage->IncrementStats(stats::invalid_clock_snapshots);
      return;
    }

    // Clock ids in the range [64, 128) are sequence-scoped and must be
    // translated to global ids via SeqScopedClockIdToGlobal() before calling
    // this function.
    PERFETTO_DCHECK(!IsReservedSeqScopedClockId(clock_id));

    // Snapshot IDs must be always monotonic.
    PERFETTO_DCHECK(vect.snapshot_ids.empty() ||
                    vect.snapshot_ids.back() < snapshot_id);

    if (!vect.timestamps_ns.empty() &&
        timestamp_ns < vect.timestamps_ns.back()) {
      // Clock is not monotonic.

      if (clock_id == trace_time_clock_id_) {
        // The trace clock cannot be non-monotonic.
        PERFETTO_ELOG("Clock sync error: the trace clock (id=%" PRIu64
                      ") is not monotonic at snapshot %" PRIu32 ". %" PRId64
                      " not >= %" PRId64 ".",
                      clock_id, snapshot_id, timestamp_ns,
                      vect.timestamps_ns.back());
        context_->storage->IncrementStats(stats::invalid_clock_snapshots);
        return;
      }

      PERFETTO_DLOG("Detected non-monotonic clock with ID %" PRIu64, clock_id);

      // For the other clocks the best thing we can do is mark it as
      // non-monotonic and refuse to use it as a source clock in the resolution
      // graph. We can still use it as a target clock, but not viceversa.
      // The concrete example is the CLOCK_REALTIME going 1h backwards during
      // daylight saving. We can still answer the question "what was the
      // REALTIME timestamp when BOOTTIME was X?" but we can't answer the
      // opposite question because there can be two valid BOOTTIME(s) for the
      // same REALTIME instant because of the 1:many relationship.
      non_monotonic_clocks_.insert(clock_id);

      // Erase all edges from the graph that start from this clock (but keep the
      // ones that end on this clock).
      auto begin = graph_.lower_bound(ClockGraphEdge{clock_id, 0, 0});
      auto end = graph_.lower_bound(ClockGraphEdge{clock_id + 1, 0, 0});
      graph_.erase(begin, end);
    }
    vect.snapshot_ids.emplace_back(snapshot_id);
    vect.timestamps_ns.emplace_back(timestamp_ns);
  }

  // Create graph edges for all the possible tuples of clocks in this snapshot.
  // If the snapshot contains clock a, b, c, d create edges [ab, ac, ad, bc, bd,
  // cd] and the symmetrical ones [ba, ca, da, bc, db, dc].
  // This is to store the information: Clock A is syncable to Clock B via the
  // snapshots of type (hash).
  // Clocks that were previously marked as non-monotonic won't be added as
  // valid sources.
  for (auto it1 = clocks.begin(); it1 != clocks.end(); ++it1) {
    auto it2 = it1;
    ++it2;
    for (; it2 != clocks.end(); ++it2) {
      if (!non_monotonic_clocks_.count(it1->clock_id))
        graph_.emplace(it1->clock_id, it2->clock_id, snapshot_hash);

      if (!non_monotonic_clocks_.count(it2->clock_id))
        graph_.emplace(it2->clock_id, it1->clock_id, snapshot_hash);
    }
  }
}

// Finds the shortest clock resolution path in the graph that allows to
// translate a timestamp from |src| to |target| clocks.
// The return value looks like the following: "If you want to convert a
// timestamp from clock C1 to C2 you need to first convert C1 -> C3 using the
// snapshot hash A, then convert C3 -> C2 via snapshot hash B".
ClockTracker::ClockPath ClockTracker::FindPath(ClockId src, ClockId target) {
  // This is a classic breadth-first search. Each node in the queue holds also
  // the full path to reach that node.
  // We assume the graph is acyclic, if it isn't the ClockPath::kMaxLen will
  // stop the search anyways.
  PERFETTO_CHECK(src != target);
  std::queue<ClockPath> queue;
  queue.emplace(src);

  while (!queue.empty()) {
    ClockPath cur_path = queue.front();
    queue.pop();

    const ClockId cur_clock_id = cur_path.last;
    if (cur_clock_id == target)
      return cur_path;

    if (cur_path.len >= ClockPath::kMaxLen)
      continue;

    // Expore all the adjacent clocks.
    // The lower_bound() below returns an iterator to the first edge that starts
    // on |cur_clock_id|. The edges are sorted by (src, target, hash).
    for (auto it = std::lower_bound(graph_.begin(), graph_.end(),
                                    ClockGraphEdge(cur_clock_id, 0, 0));
         it != graph_.end() && std::get<0>(*it) == cur_clock_id; ++it) {
      ClockId next_clock_id = std::get<1>(*it);
      SnapshotHash hash = std::get<2>(*it);
      queue.push(ClockPath(cur_path, next_clock_id, hash));
    }
  }
  return ClockPath();  // invalid path.
}

base::Optional<int64_t> ClockTracker::ConvertSlowpath(ClockId src_clock_id,
                                                      int64_t src_timestamp,
                                                      ClockId target_clock_id) {
  PERFETTO_DCHECK(!IsReservedSeqScopedClockId(src_clock_id));
  PERFETTO_DCHECK(!IsReservedSeqScopedClockId(target_clock_id));

  context_->storage->IncrementStats(stats::clock_sync_cache_miss);

  ClockPath path = FindPath(src_clock_id, target_clock_id);
  if (!path.valid()) {
    // Too many logs maybe emitted when path is invalid.
    static std::atomic<uint32_t> dlog_count = 0;
    if (dlog_count++ < 10) {
      PERFETTO_DLOG("No path from clock %" PRIu64 " to %" PRIu64
                    " at timestamp %" PRId64,
                    src_clock_id, target_clock_id, src_timestamp);
    }
    context_->storage->IncrementStats(stats::clock_sync_failure);
    return base::nullopt;
  }

  // We can cache only single-path resolutions between two clocks.
  // Caching multi-path resolutions is harder because the (src,target) tuple
  // is not enough as a cache key: at any step the |ns| value can yield to a
  // different choice of the next snapshot. Multi-path resolutions don't seem
  // too frequent these days, so we focus only on caching the more frequent
  // one-step resolutions (typically from any clock to the trace clock).
  const bool cacheable = path.len == 1;
  CachedClockPath cache_entry{};

  // Iterate trough the path found and translate timestamps onto the new clock
  // domain on each step, until the target domain is reached.
  ClockDomain* src_domain = GetClock(src_clock_id);
  int64_t ns = src_domain->ToNs(src_timestamp);
  for (uint32_t i = 0; i < path.len; ++i) {
    const ClockGraphEdge edge = path.at(i);
    ClockDomain* cur_clock = GetClock(std::get<0>(edge));
    ClockDomain* next_clock = GetClock(std::get<1>(edge));
    const SnapshotHash hash = std::get<2>(edge);

    // Find the closest timestamp within the snapshots of the source clock.
    const ClockSnapshots& cur_snap = cur_clock->GetSnapshot(hash);
    const auto& ts_vec = cur_snap.timestamps_ns;
    auto it = std::upper_bound(ts_vec.begin(), ts_vec.end(), ns);
    if (it != ts_vec.begin())
      --it;

    // Now lookup the snapshot id that matches the closest timestamp.
    size_t index = static_cast<size_t>(std::distance(ts_vec.begin(), it));
    PERFETTO_DCHECK(index < ts_vec.size());
    PERFETTO_DCHECK(cur_snap.snapshot_ids.size() == ts_vec.size());
    uint32_t snapshot_id = cur_snap.snapshot_ids[index];

    // And use that to retrieve the corresponding time in the next clock domain.
    // The snapshot id must exist in the target clock domain. If it doesn't
    // either the hash logic or the pathfinding logic are bugged.
    // This can also happen if the checks in AddSnapshot fail and we skip part
    // of the snapshot.
    const ClockSnapshots& next_snap = next_clock->GetSnapshot(hash);

    // Using std::lower_bound because snapshot_ids is sorted, so we can do
    // a binary search. std::find would do a linear scan.
    auto next_it = std::lower_bound(next_snap.snapshot_ids.begin(),
                                    next_snap.snapshot_ids.end(), snapshot_id);
    if (next_it == next_snap.snapshot_ids.end() || *next_it != snapshot_id) {
      PERFETTO_DFATAL("Snapshot does not exist in clock domain.");
      continue;
    }
    size_t next_index = static_cast<size_t>(
        std::distance(next_snap.snapshot_ids.begin(), next_it));
    PERFETTO_DCHECK(next_index < next_snap.snapshot_ids.size());
    int64_t next_timestamp_ns = next_snap.timestamps_ns[next_index];

    // The translated timestamp is the relative delta of the source timestamp
    // from the closest snapshot found (ns - *it), plus the timestamp in
    // the new clock domain for the same snapshot id.
    const int64_t adj = next_timestamp_ns - *it;
    ns += adj;

    // On the first iteration, keep track of the bounds for the cache entry.
    // This will allow future Convert() calls to skip the pathfinder logic
    // as long as the query stays within the bound.
    if (cacheable) {
      PERFETTO_DCHECK(i == 0);
      const int64_t kInt64Min = std::numeric_limits<int64_t>::min();
      const int64_t kInt64Max = std::numeric_limits<int64_t>::max();
      cache_entry.min_ts_ns = it == ts_vec.begin() ? kInt64Min : *it;
      auto ubound = it + 1;
      cache_entry.max_ts_ns = ubound == ts_vec.end() ? kInt64Max : *ubound;
      cache_entry.translation_ns = adj;
    }

    // The last clock in the path must be the target clock.
    PERFETTO_DCHECK(i < path.len - 1 || std::get<1>(edge) == target_clock_id);
  }

  if (cacheable) {
    cache_entry.src = src_clock_id;
    cache_entry.src_domain = src_domain;
    cache_entry.target = target_clock_id;
    cache_[rnd_() % cache_.size()] = cache_entry;
  }

  return ns;
}

}  // namespace trace_processor
}  // namespace perfetto
<commit_msg>Fix clock_tracker.cc am: 5dc147f282 am: f2faa3dd19 am: caf328c24a am: 55af9a1d07 am: 3e6b048077<commit_after>/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/trace_processor/importers/common/clock_tracker.h"

#include <inttypes.h>

#include <algorithm>
#include <atomic>
#include <queue>

#include "perfetto/base/logging.h"
#include "perfetto/ext/base/hash.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/types/trace_processor_context.h"

#include "protos/perfetto/common/builtin_clock.pbzero.h"
#include "protos/perfetto/trace/clock_snapshot.pbzero.h"

namespace perfetto {
namespace trace_processor {

using Clock = protos::pbzero::ClockSnapshot::Clock;

ClockTracker::ClockTracker(TraceProcessorContext* ctx)
    : context_(ctx),
      trace_time_clock_id_(protos::pbzero::BUILTIN_CLOCK_BOOTTIME) {}

ClockTracker::~ClockTracker() = default;

void ClockTracker::AddSnapshot(const std::vector<ClockValue>& clocks) {
  const auto snapshot_id = cur_snapshot_id_++;

  // Clear the cache
  cache_.fill({});

  // Compute the fingerprint of the snapshot by hashing all clock ids. This is
  // used by the clock pathfinding logic.
  base::Hash hasher;
  for (const auto& clock : clocks)
    hasher.Update(clock.clock_id);
  const auto snapshot_hash = static_cast<SnapshotHash>(hasher.digest());

  // Add a new entry in each clock's snapshot vector.
  for (const auto& clock : clocks) {
    ClockId clock_id = clock.clock_id;
    ClockDomain& domain = clocks_[clock_id];
    if (domain.snapshots.empty()) {
      if (clock.is_incremental && !ClockIsSeqScoped(clock_id)) {
        PERFETTO_ELOG("Clock sync error: the global clock with id=%" PRIu64
                      " cannot use incremental encoding; this is only "
                      "supported for sequence-scoped clocks.",
                      clock_id);
        context_->storage->IncrementStats(stats::invalid_clock_snapshots);
        return;
      }
      domain.unit_multiplier_ns = clock.unit_multiplier_ns;
      domain.is_incremental = clock.is_incremental;
    } else if (PERFETTO_UNLIKELY(
                   domain.unit_multiplier_ns != clock.unit_multiplier_ns ||
                   domain.is_incremental != clock.is_incremental)) {
      PERFETTO_ELOG("Clock sync error: the clock domain with id=%" PRIu64
                    " (unit=%" PRIu64
                    ", incremental=%d), was previously registered with "
                    "different properties (unit=%" PRIu64 ", incremental=%d).",
                    clock_id, clock.unit_multiplier_ns, clock.is_incremental,
                    domain.unit_multiplier_ns, domain.is_incremental);
      context_->storage->IncrementStats(stats::invalid_clock_snapshots);
      return;
    }
    const int64_t timestamp_ns =
        clock.absolute_timestamp * domain.unit_multiplier_ns;
    domain.last_timestamp_ns = timestamp_ns;

    ClockSnapshots& vect = domain.snapshots[snapshot_hash];
    if (!vect.snapshot_ids.empty() &&
        PERFETTO_UNLIKELY(vect.snapshot_ids.back() == snapshot_id)) {
      PERFETTO_ELOG("Clock sync error: duplicate clock domain with id=%" PRIu64
                    " at snapshot %" PRIu32 ".",
                    clock_id, snapshot_id);
      context_->storage->IncrementStats(stats::invalid_clock_snapshots);
      return;
    }

    // Clock ids in the range [64, 128) are sequence-scoped and must be
    // translated to global ids via SeqScopedClockIdToGlobal() before calling
    // this function.
    PERFETTO_DCHECK(!IsReservedSeqScopedClockId(clock_id));

    // Snapshot IDs must be always monotonic.
    PERFETTO_DCHECK(vect.snapshot_ids.empty() ||
                    vect.snapshot_ids.back() < snapshot_id);

    if (!vect.timestamps_ns.empty() &&
        timestamp_ns < vect.timestamps_ns.back()) {
      // Clock is not monotonic.

      if (clock_id == trace_time_clock_id_) {
        // The trace clock cannot be non-monotonic.
        PERFETTO_ELOG("Clock sync error: the trace clock (id=%" PRIu64
                      ") is not monotonic at snapshot %" PRIu32 ". %" PRId64
                      " not >= %" PRId64 ".",
                      clock_id, snapshot_id, timestamp_ns,
                      vect.timestamps_ns.back());
        context_->storage->IncrementStats(stats::invalid_clock_snapshots);
        return;
      }

      PERFETTO_DLOG("Detected non-monotonic clock with ID %" PRIu64, clock_id);

      // For the other clocks the best thing we can do is mark it as
      // non-monotonic and refuse to use it as a source clock in the resolution
      // graph. We can still use it as a target clock, but not viceversa.
      // The concrete example is the CLOCK_REALTIME going 1h backwards during
      // daylight saving. We can still answer the question "what was the
      // REALTIME timestamp when BOOTTIME was X?" but we can't answer the
      // opposite question because there can be two valid BOOTTIME(s) for the
      // same REALTIME instant because of the 1:many relationship.
      non_monotonic_clocks_.insert(clock_id);

      // Erase all edges from the graph that start from this clock (but keep the
      // ones that end on this clock).
      auto begin = graph_.lower_bound(ClockGraphEdge{clock_id, 0, 0});
      auto end = graph_.lower_bound(ClockGraphEdge{clock_id + 1, 0, 0});
      graph_.erase(begin, end);
    }
    vect.snapshot_ids.emplace_back(snapshot_id);
    vect.timestamps_ns.emplace_back(timestamp_ns);
  }

  // Create graph edges for all the possible tuples of clocks in this snapshot.
  // If the snapshot contains clock a, b, c, d create edges [ab, ac, ad, bc, bd,
  // cd] and the symmetrical ones [ba, ca, da, bc, db, dc].
  // This is to store the information: Clock A is syncable to Clock B via the
  // snapshots of type (hash).
  // Clocks that were previously marked as non-monotonic won't be added as
  // valid sources.
  for (auto it1 = clocks.begin(); it1 != clocks.end(); ++it1) {
    auto it2 = it1;
    ++it2;
    for (; it2 != clocks.end(); ++it2) {
      if (!non_monotonic_clocks_.count(it1->clock_id))
        graph_.emplace(it1->clock_id, it2->clock_id, snapshot_hash);

      if (!non_monotonic_clocks_.count(it2->clock_id))
        graph_.emplace(it2->clock_id, it1->clock_id, snapshot_hash);
    }
  }
}

// Finds the shortest clock resolution path in the graph that allows to
// translate a timestamp from |src| to |target| clocks.
// The return value looks like the following: "If you want to convert a
// timestamp from clock C1 to C2 you need to first convert C1 -> C3 using the
// snapshot hash A, then convert C3 -> C2 via snapshot hash B".
ClockTracker::ClockPath ClockTracker::FindPath(ClockId src, ClockId target) {
  // This is a classic breadth-first search. Each node in the queue holds also
  // the full path to reach that node.
  // We assume the graph is acyclic, if it isn't the ClockPath::kMaxLen will
  // stop the search anyways.
  PERFETTO_CHECK(src != target);
  std::queue<ClockPath> queue;
  queue.emplace(src);

  while (!queue.empty()) {
    ClockPath cur_path = queue.front();
    queue.pop();

    const ClockId cur_clock_id = cur_path.last;
    if (cur_clock_id == target)
      return cur_path;

    if (cur_path.len >= ClockPath::kMaxLen)
      continue;

    // Expore all the adjacent clocks.
    // The lower_bound() below returns an iterator to the first edge that starts
    // on |cur_clock_id|. The edges are sorted by (src, target, hash).
    for (auto it = std::lower_bound(graph_.begin(), graph_.end(),
                                    ClockGraphEdge(cur_clock_id, 0, 0));
         it != graph_.end() && std::get<0>(*it) == cur_clock_id; ++it) {
      ClockId next_clock_id = std::get<1>(*it);
      SnapshotHash hash = std::get<2>(*it);
      queue.push(ClockPath(cur_path, next_clock_id, hash));
    }
  }
  return ClockPath();  // invalid path.
}

base::Optional<int64_t> ClockTracker::ConvertSlowpath(ClockId src_clock_id,
                                                      int64_t src_timestamp,
                                                      ClockId target_clock_id) {
  PERFETTO_DCHECK(!IsReservedSeqScopedClockId(src_clock_id));
  PERFETTO_DCHECK(!IsReservedSeqScopedClockId(target_clock_id));

  context_->storage->IncrementStats(stats::clock_sync_cache_miss);

  ClockPath path = FindPath(src_clock_id, target_clock_id);
  if (!path.valid()) {
    // Too many logs maybe emitted when path is invalid.
    static std::atomic<uint32_t> dlog_count(0);
    if (dlog_count++ < 10) {
      PERFETTO_DLOG("No path from clock %" PRIu64 " to %" PRIu64
                    " at timestamp %" PRId64,
                    src_clock_id, target_clock_id, src_timestamp);
    }
    context_->storage->IncrementStats(stats::clock_sync_failure);
    return base::nullopt;
  }

  // We can cache only single-path resolutions between two clocks.
  // Caching multi-path resolutions is harder because the (src,target) tuple
  // is not enough as a cache key: at any step the |ns| value can yield to a
  // different choice of the next snapshot. Multi-path resolutions don't seem
  // too frequent these days, so we focus only on caching the more frequent
  // one-step resolutions (typically from any clock to the trace clock).
  const bool cacheable = path.len == 1;
  CachedClockPath cache_entry{};

  // Iterate trough the path found and translate timestamps onto the new clock
  // domain on each step, until the target domain is reached.
  ClockDomain* src_domain = GetClock(src_clock_id);
  int64_t ns = src_domain->ToNs(src_timestamp);
  for (uint32_t i = 0; i < path.len; ++i) {
    const ClockGraphEdge edge = path.at(i);
    ClockDomain* cur_clock = GetClock(std::get<0>(edge));
    ClockDomain* next_clock = GetClock(std::get<1>(edge));
    const SnapshotHash hash = std::get<2>(edge);

    // Find the closest timestamp within the snapshots of the source clock.
    const ClockSnapshots& cur_snap = cur_clock->GetSnapshot(hash);
    const auto& ts_vec = cur_snap.timestamps_ns;
    auto it = std::upper_bound(ts_vec.begin(), ts_vec.end(), ns);
    if (it != ts_vec.begin())
      --it;

    // Now lookup the snapshot id that matches the closest timestamp.
    size_t index = static_cast<size_t>(std::distance(ts_vec.begin(), it));
    PERFETTO_DCHECK(index < ts_vec.size());
    PERFETTO_DCHECK(cur_snap.snapshot_ids.size() == ts_vec.size());
    uint32_t snapshot_id = cur_snap.snapshot_ids[index];

    // And use that to retrieve the corresponding time in the next clock domain.
    // The snapshot id must exist in the target clock domain. If it doesn't
    // either the hash logic or the pathfinding logic are bugged.
    // This can also happen if the checks in AddSnapshot fail and we skip part
    // of the snapshot.
    const ClockSnapshots& next_snap = next_clock->GetSnapshot(hash);

    // Using std::lower_bound because snapshot_ids is sorted, so we can do
    // a binary search. std::find would do a linear scan.
    auto next_it = std::lower_bound(next_snap.snapshot_ids.begin(),
                                    next_snap.snapshot_ids.end(), snapshot_id);
    if (next_it == next_snap.snapshot_ids.end() || *next_it != snapshot_id) {
      PERFETTO_DFATAL("Snapshot does not exist in clock domain.");
      continue;
    }
    size_t next_index = static_cast<size_t>(
        std::distance(next_snap.snapshot_ids.begin(), next_it));
    PERFETTO_DCHECK(next_index < next_snap.snapshot_ids.size());
    int64_t next_timestamp_ns = next_snap.timestamps_ns[next_index];

    // The translated timestamp is the relative delta of the source timestamp
    // from the closest snapshot found (ns - *it), plus the timestamp in
    // the new clock domain for the same snapshot id.
    const int64_t adj = next_timestamp_ns - *it;
    ns += adj;

    // On the first iteration, keep track of the bounds for the cache entry.
    // This will allow future Convert() calls to skip the pathfinder logic
    // as long as the query stays within the bound.
    if (cacheable) {
      PERFETTO_DCHECK(i == 0);
      const int64_t kInt64Min = std::numeric_limits<int64_t>::min();
      const int64_t kInt64Max = std::numeric_limits<int64_t>::max();
      cache_entry.min_ts_ns = it == ts_vec.begin() ? kInt64Min : *it;
      auto ubound = it + 1;
      cache_entry.max_ts_ns = ubound == ts_vec.end() ? kInt64Max : *ubound;
      cache_entry.translation_ns = adj;
    }

    // The last clock in the path must be the target clock.
    PERFETTO_DCHECK(i < path.len - 1 || std::get<1>(edge) == target_clock_id);
  }

  if (cacheable) {
    cache_entry.src = src_clock_id;
    cache_entry.src_domain = src_domain;
    cache_entry.target = target_clock_id;
    cache_[rnd_() % cache_.size()] = cache_entry;
  }

  return ns;
}

}  // namespace trace_processor
}  // namespace perfetto
<|endoftext|>


<commit_before>// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2014 projectchrono.org
// All right reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Authors: Radu Serban
// =============================================================================
//
// Main driver function for a vehicle specified through JSON files.
//
// If using the Irrlicht interface, driver inputs are obtained from the keyboard.
//
// The vehicle reference frame has Z up, X towards the front of the vehicle, and
// Y pointing to the left.
//
// =============================================================================

#include <vector>

#include "core/ChFileutils.h"
#include "core/ChStream.h"
#include "core/ChRealtimeStep.h"
#include "physics/ChSystem.h"
#include "physics/ChLinkDistance.h"

#include "ChronoT_config.h"

#include "utils/ChUtilsInputOutput.h"
#include "utils/ChUtilsData.h"

#include "subsys/vehicle/Vehicle.h"
#include "subsys/powertrain/SimplePowertrain.h"
#include "subsys/driver/ChDataDriver.h"
#include "subsys/tire/RigidTire.h"
#include "subsys/terrain/RigidTerrain.h"

// If Irrlicht support is available...
#if IRRLICHT_ENABLED
  // ...include additional headers
# include "unit_IRRLICHT/ChIrrApp.h"
# include "subsys/driver/ChIrrGuiDriver.h"

  // ...and specify whether the demo should actually use Irrlicht
# define USE_IRRLICHT
#endif

using namespace chrono;

// =============================================================================

// JSON file for vehicle model
//std::string vehicle_file = utils::GetModelDataFile("hmmwv/vehicle/HMMWV_Vehicle.json");
std::string vehicle_file = utils::GetModelDataFile("hmmwv/vehicle/HMMWV_Vehicle_A.json");
//std::string vehicle_file = utils::GetModelDataFile("generic/vehicle/Vehicle_DoubleWishbones.json");
//std::string vehicle_file = utils::GetModelDataFile("generic/vehicle/Vehicle_MultiLinks.json");
//std::string vehicle_file = utils::GetModelDataFile("generic/vehicle/Vehicle_SolidAxles.json");
//std::string vehicle_file = utils::GetModelDataFile("generic/vehicle/Vehicle_ThreeAxles.json");

// JSON files for tire models (rigid) and powertrain (simple)
std::string rigidtire_file = utils::GetModelDataFile("hmmwv/tire/HMMWV_RigidTire.json");
std::string simplepowertrain_file = utils::GetModelDataFile("hmmwv/powertrain/HMMWV_SimplePowertrain.json");

// Driver input file (if not using Irrlicht)
std::string driver_file = utils::GetModelDataFile("generic/driver/Sample_Maneuver.txt");

// Initial vehicle position
ChVector<> initLoc(0, 0, 1.0);

// Initial vehicle orientation
ChQuaternion<> initRot(1, 0, 0, 0);
//ChQuaternion<> initRot(0.866025, 0, 0, 0.5);
//ChQuaternion<> initRot(0.7071068, 0, 0, 0.7071068);
//ChQuaternion<> initRot(0.25882, 0, 0, 0.965926);
//ChQuaternion<> initRot(0, 0, 0, 1);

// Rigid terrain dimensions
double terrainHeight = 0;
double terrainLength = 100.0;   // size in X direction
double terrainWidth  = 100.0;   // size in Y direction

// Simulation step size
double step_size = 0.001;

// Time interval between two render frames
double render_step_size = 1.0 / 50;   // FPS = 50

// Time interval between two output frames
double output_step_size = 1.0 / 1;    // once a second

#ifdef USE_IRRLICHT
  // Point on chassis tracked by the camera
  ChVector<> trackPoint(0.0, 0.0, 1.75);
#else
  double tend = 20.0;

  const std::string out_dir = "../VEHICLE";
  const std::string pov_dir = out_dir + "/POVRAY";
#endif

// =============================================================================

int main(int argc, char* argv[])
{
  SetChronoDataPath(CHRONO_DATA_DIR);

  // --------------------------
  // Create the various modules
  // --------------------------

  // Create the vehicle system
  Vehicle vehicle(vehicle_file, false);
  vehicle.Initialize(ChCoordsys<>(initLoc, initRot));

  // Create the ground
  RigidTerrain terrain(vehicle, terrainHeight, terrainLength, terrainWidth, 0.8);

  // Create and initialize the powertrain system
  SimplePowertrain powertrain(simplepowertrain_file);
  powertrain.Initialize();

  // Create and initialize the tires
  int num_axles = vehicle.GetNumberAxles();
  int num_wheels = 2 * num_axles;
  std::vector<ChSharedPtr<ChTire> > tires(num_wheels);

  for (int i = 0; i < num_wheels; i++) {
    ChSharedPtr<RigidTire> tire(new RigidTire(rigidtire_file, terrain));
    tire->Initialize(vehicle.GetWheelBody(i));
    tires[i] = tire;
  }

#ifdef USE_IRRLICHT
  irr::ChIrrApp application(&vehicle,
                            L"Vehicle demo",
                            irr::core::dimension2d<irr::u32>(1000, 800),
                            false,
                            true);

  // make a skybox that has Z pointing up (default application.AddTypicalSky() makes Y up)
  std::string mtexturedir = GetChronoDataFile("skybox/");
  std::string str_lf = mtexturedir + "sky_lf.jpg";
  std::string str_up = mtexturedir + "sky_up.jpg";
  std::string str_dn = mtexturedir + "sky_dn.jpg";
  irr::video::ITexture* map_skybox_side =
      application.GetVideoDriver()->getTexture(str_lf.c_str());
  irr::scene::ISceneNode* mbox = application.GetSceneManager()->addSkyBoxSceneNode(
      application.GetVideoDriver()->getTexture(str_up.c_str()),
      application.GetVideoDriver()->getTexture(str_dn.c_str()),
      map_skybox_side,
      map_skybox_side,
      map_skybox_side,
      map_skybox_side);
  mbox->setRotation( irr::core::vector3df(90,0,0));

  bool do_shadows = true; // shadow map is experimental
  irr::scene::ILightSceneNode* mlight = 0;

  if (do_shadows)
  {
    mlight = application.AddLightWithShadow(
      irr::core::vector3df(10.f, 30.f, 60.f),
      irr::core::vector3df(0.f, 0.f, 0.f),
      150, 60, 80, 15, 512, irr::video::SColorf(1, 1, 1), false, false);
  }
  else
  {
    application.AddTypicalLights(
      irr::core::vector3df(30.f, -30.f, 100.f),
      irr::core::vector3df(30.f, 50.f, 100.f),
      250, 130);
  }

  application.SetTimestep(step_size);

  ChIrrGuiDriver driver(application, vehicle, powertrain, trackPoint, 6.0, 0.5, true);

  // Set the time response for steering and throttle keyboard inputs.
  // NOTE: this is not exact, since we do not render quite at the specified FPS.
  double steering_time = 1.0;  // time to go from 0 to +1 (or from 0 to -1)
  double throttle_time = 1.0;  // time to go from 0 to +1
  double braking_time = 0.3;   // time to go from 0 to +1
  driver.SetSteeringDelta(render_step_size / steering_time);
  driver.SetThrottleDelta(render_step_size / throttle_time);
  driver.SetBrakingDelta(render_step_size / braking_time);

  // Set up the assets for rendering
  application.AssetBindAll();
  application.AssetUpdateAll();
  if (do_shadows)
  {
    application.AddShadowAll();
  }
#else
  ChDataDriver driver(driver_file);
#endif

  // ---------------
  // Simulation loop
  // ---------------

  // Inter-module communication data
  ChTireForces   tire_forces(num_wheels);
  ChWheelStates  wheel_states(num_wheels);
  double         driveshaft_speed;
  double         powertrain_torque;
  double         throttle_input;
  double         steering_input;
  double         braking_input;

  // Number of simulation steps between two 3D view render frames
  int render_steps = (int)std::ceil(render_step_size / step_size);

  // Number of simulation steps between two output frames
  int output_steps = (int)std::ceil(output_step_size / step_size);

  // Initialize simulation frame counter and simulation time
  int step_number = 0;
  double time = 0;

#ifdef USE_IRRLICHT

  ChRealtimeStepTimer realtime_timer;

  while (application.GetDevice()->run())
  {
    // update the position of the shadow mapping so that it follows the car
    if (do_shadows)
    {
      ChVector<> lightaim = vehicle.GetChassisPos();
      ChVector<> lightpos = vehicle.GetChassisPos() + ChVector<>(10, 30, 60);
      irr::core::vector3df mlightpos((irr::f32)lightpos.x, (irr::f32)lightpos.y, (irr::f32)lightpos.z);
      irr::core::vector3df mlightaim((irr::f32)lightaim.x, (irr::f32)lightaim.y, (irr::f32)lightaim.z);
      application.GetEffects()->getShadowLight(0).setPosition(mlightpos);
      application.GetEffects()->getShadowLight(0).setTarget(mlightaim);
      mlight->setPosition(mlightpos);
    }

    // Render scene
    if (step_number % render_steps == 0) {
      application.GetVideoDriver()->beginScene(true, true, irr::video::SColor(255, 140, 161, 192));
      driver.DrawAll();
      application.GetVideoDriver()->endScene();
    }

    // Collect output data from modules (for inter-module communication)
    throttle_input = driver.GetThrottle();
    steering_input = driver.GetSteering();
    braking_input = driver.GetBraking();
    powertrain_torque = powertrain.GetOutputTorque();
    driveshaft_speed = vehicle.GetDriveshaftSpeed();
    for (int i = 0; i < num_wheels; i++) {
      tire_forces[i] = tires[i]->GetTireForce();
      wheel_states[i] = vehicle.GetWheelState(i);
    }

    // Update modules (process inputs from other modules)
    time = vehicle.GetChTime();
    driver.Update(time);
    powertrain.Update(time, throttle_input, driveshaft_speed);
    vehicle.Update(time, steering_input, braking_input, powertrain_torque, tire_forces);
    terrain.Update(time);
    for (int i = 0; i < num_wheels; i++)
      tires[i]->Update(time, wheel_states[i]);

    // Advance simulation for one timestep for all modules
    double step = realtime_timer.SuggestSimulationStep(step_size);
    driver.Advance(step);
    powertrain.Advance(step);
    vehicle.Advance(step);
    terrain.Advance(step);
    for (int i = 0; i < num_wheels; i++)
      tires[i]->Advance(step);

    // Increment frame number
    step_number++;
  }

  application.GetDevice()->drop();

#else

  int render_frame = 0;

  if(ChFileutils::MakeDirectory(out_dir.c_str()) < 0) {
    std::cout << "Error creating directory " << out_dir << std::endl;
    return 1;
  }
  if(ChFileutils::MakeDirectory(pov_dir.c_str()) < 0) {
    std::cout << "Error creating directory " << pov_dir << std::endl;
    return 1;
  }

  vehicle.ExportMeshPovray(out_dir);

  char filename[100];

  while (time < tend)
  {
    if (step_number % render_steps == 0) {
      // Output render data
      sprintf(filename, "%s/data_%03d.dat", pov_dir.c_str(), render_frame + 1);
      utils::WriteShapesPovray(&vehicle, filename);
      std::cout << "Output frame:   " << render_frame << std::endl;
      std::cout << "Sim frame:      " << step_number << std::endl;
      std::cout << "Time:           " << time << std::endl;
      std::cout << "   throttle: " << driver.GetThrottle()
                << "   steering: " << driver.GetSteering()
                << "   braking:  " << driver.GetBraking() << std::endl;
      std::cout << std::endl;
      render_frame++;
    }

    // Collect output data from modules (for inter-module communication)
    throttle_input = driver.GetThrottle();
    steering_input = driver.GetSteering();
    braking_input = driver.GetBraking();
    powertrain_torque = powertrain.GetOutputTorque();
    driveshaft_speed = vehicle.GetDriveshaftSpeed();
    for (int i = 0; i < num_wheels; i++) {
      tire_forces[i] = tires[i]->GetTireForce();
      wheel_states[i] = vehicle.GetWheelState(i);
    }

    // Update modules (process inputs from other modules)
    time = vehicle.GetChTime();
    driver.Update(time);
    powertrain.Update(time, throttle_input, driveshaft_speed);
    vehicle.Update(time, steering_input, braking_input, powertrain_torque, tire_forces);
    terrain.Update(time);
    for (int i = 0; i < num_wheels; i++)
      tires[i]->Update(time, wheel_states[i]);

    // Update modules (process inputs from other modules)
    time = vehicle.GetChTime();
    driver.Update(time);
    powertrain.Update(time, throttle_input, driveshaft_speed);
    vehicle.Update(time, steering_input, braking_input, powertrain_torque, tire_forces);
    terrain.Update(time);
    for (int i = 0; i < num_wheels; i++)
      tires[i]->Update(time, wheel_states[i]);

    // Advance simulation for one timestep for all modules
    driver.Advance(step_size);
    powertrain.Advance(step_size);
    vehicle.Advance(step_size);
    terrain.Advance(step_size);
    for (int i = 0; i < num_wheels; i++)
      tires[i]->Advance(step_size);

    // Increment frame number
    step_number++;
  }

#endif

  return 0;
}
<commit_msg>Removed the ADAMS HMMWV from the demo_Vehicle choices.<commit_after>// =============================================================================
// PROJECT CHRONO - http://projectchrono.org
//
// Copyright (c) 2014 projectchrono.org
// All right reserved.
//
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file at the top level of the distribution and at
// http://projectchrono.org/license-chrono.txt.
//
// =============================================================================
// Authors: Radu Serban
// =============================================================================
//
// Main driver function for a vehicle specified through JSON files.
//
// If using the Irrlicht interface, driver inputs are obtained from the keyboard.
//
// The vehicle reference frame has Z up, X towards the front of the vehicle, and
// Y pointing to the left.
//
// =============================================================================

#include <vector>

#include "core/ChFileutils.h"
#include "core/ChStream.h"
#include "core/ChRealtimeStep.h"
#include "physics/ChSystem.h"
#include "physics/ChLinkDistance.h"

#include "ChronoT_config.h"

#include "utils/ChUtilsInputOutput.h"
#include "utils/ChUtilsData.h"

#include "subsys/vehicle/Vehicle.h"
#include "subsys/powertrain/SimplePowertrain.h"
#include "subsys/driver/ChDataDriver.h"
#include "subsys/tire/RigidTire.h"
#include "subsys/terrain/RigidTerrain.h"

// If Irrlicht support is available...
#if IRRLICHT_ENABLED
  // ...include additional headers
# include "unit_IRRLICHT/ChIrrApp.h"
# include "subsys/driver/ChIrrGuiDriver.h"

  // ...and specify whether the demo should actually use Irrlicht
# define USE_IRRLICHT
#endif

using namespace chrono;

// =============================================================================

// JSON file for vehicle model
std::string vehicle_file = utils::GetModelDataFile("hmmwv/vehicle/HMMWV_Vehicle.json");
//std::string vehicle_file = utils::GetModelDataFile("generic/vehicle/Vehicle_DoubleWishbones.json");
//std::string vehicle_file = utils::GetModelDataFile("generic/vehicle/Vehicle_MultiLinks.json");
//std::string vehicle_file = utils::GetModelDataFile("generic/vehicle/Vehicle_SolidAxles.json");
//std::string vehicle_file = utils::GetModelDataFile("generic/vehicle/Vehicle_ThreeAxles.json");

// JSON files for tire models (rigid) and powertrain (simple)
std::string rigidtire_file = utils::GetModelDataFile("hmmwv/tire/HMMWV_RigidTire.json");
std::string simplepowertrain_file = utils::GetModelDataFile("hmmwv/powertrain/HMMWV_SimplePowertrain.json");

// Driver input file (if not using Irrlicht)
std::string driver_file = utils::GetModelDataFile("generic/driver/Sample_Maneuver.txt");

// Initial vehicle position
ChVector<> initLoc(0, 0, 1.0);

// Initial vehicle orientation
ChQuaternion<> initRot(1, 0, 0, 0);
//ChQuaternion<> initRot(0.866025, 0, 0, 0.5);
//ChQuaternion<> initRot(0.7071068, 0, 0, 0.7071068);
//ChQuaternion<> initRot(0.25882, 0, 0, 0.965926);
//ChQuaternion<> initRot(0, 0, 0, 1);

// Rigid terrain dimensions
double terrainHeight = 0;
double terrainLength = 100.0;   // size in X direction
double terrainWidth  = 100.0;   // size in Y direction

// Simulation step size
double step_size = 0.001;

// Time interval between two render frames
double render_step_size = 1.0 / 50;   // FPS = 50

// Time interval between two output frames
double output_step_size = 1.0 / 1;    // once a second

#ifdef USE_IRRLICHT
  // Point on chassis tracked by the camera
  ChVector<> trackPoint(0.0, 0.0, 1.75);
#else
  double tend = 20.0;

  const std::string out_dir = "../VEHICLE";
  const std::string pov_dir = out_dir + "/POVRAY";
#endif

// =============================================================================

int main(int argc, char* argv[])
{
  SetChronoDataPath(CHRONO_DATA_DIR);

  // --------------------------
  // Create the various modules
  // --------------------------

  // Create the vehicle system
  Vehicle vehicle(vehicle_file, false);
  vehicle.Initialize(ChCoordsys<>(initLoc, initRot));

  // Create the ground
  RigidTerrain terrain(vehicle, terrainHeight, terrainLength, terrainWidth, 0.8);

  // Create and initialize the powertrain system
  SimplePowertrain powertrain(simplepowertrain_file);
  powertrain.Initialize();

  // Create and initialize the tires
  int num_axles = vehicle.GetNumberAxles();
  int num_wheels = 2 * num_axles;
  std::vector<ChSharedPtr<ChTire> > tires(num_wheels);

  for (int i = 0; i < num_wheels; i++) {
    ChSharedPtr<RigidTire> tire(new RigidTire(rigidtire_file, terrain));
    tire->Initialize(vehicle.GetWheelBody(i));
    tires[i] = tire;
  }

#ifdef USE_IRRLICHT
  irr::ChIrrApp application(&vehicle,
                            L"Vehicle demo",
                            irr::core::dimension2d<irr::u32>(1000, 800),
                            false,
                            true);

  // make a skybox that has Z pointing up (default application.AddTypicalSky() makes Y up)
  std::string mtexturedir = GetChronoDataFile("skybox/");
  std::string str_lf = mtexturedir + "sky_lf.jpg";
  std::string str_up = mtexturedir + "sky_up.jpg";
  std::string str_dn = mtexturedir + "sky_dn.jpg";
  irr::video::ITexture* map_skybox_side =
      application.GetVideoDriver()->getTexture(str_lf.c_str());
  irr::scene::ISceneNode* mbox = application.GetSceneManager()->addSkyBoxSceneNode(
      application.GetVideoDriver()->getTexture(str_up.c_str()),
      application.GetVideoDriver()->getTexture(str_dn.c_str()),
      map_skybox_side,
      map_skybox_side,
      map_skybox_side,
      map_skybox_side);
  mbox->setRotation( irr::core::vector3df(90,0,0));

  bool do_shadows = true; // shadow map is experimental
  irr::scene::ILightSceneNode* mlight = 0;

  if (do_shadows)
  {
    mlight = application.AddLightWithShadow(
      irr::core::vector3df(10.f, 30.f, 60.f),
      irr::core::vector3df(0.f, 0.f, 0.f),
      150, 60, 80, 15, 512, irr::video::SColorf(1, 1, 1), false, false);
  }
  else
  {
    application.AddTypicalLights(
      irr::core::vector3df(30.f, -30.f, 100.f),
      irr::core::vector3df(30.f, 50.f, 100.f),
      250, 130);
  }

  application.SetTimestep(step_size);

  ChIrrGuiDriver driver(application, vehicle, powertrain, trackPoint, 6.0, 0.5, true);

  // Set the time response for steering and throttle keyboard inputs.
  // NOTE: this is not exact, since we do not render quite at the specified FPS.
  double steering_time = 1.0;  // time to go from 0 to +1 (or from 0 to -1)
  double throttle_time = 1.0;  // time to go from 0 to +1
  double braking_time = 0.3;   // time to go from 0 to +1
  driver.SetSteeringDelta(render_step_size / steering_time);
  driver.SetThrottleDelta(render_step_size / throttle_time);
  driver.SetBrakingDelta(render_step_size / braking_time);

  // Set up the assets for rendering
  application.AssetBindAll();
  application.AssetUpdateAll();
  if (do_shadows)
  {
    application.AddShadowAll();
  }
#else
  ChDataDriver driver(driver_file);
#endif

  // ---------------
  // Simulation loop
  // ---------------

  // Inter-module communication data
  ChTireForces   tire_forces(num_wheels);
  ChWheelStates  wheel_states(num_wheels);
  double         driveshaft_speed;
  double         powertrain_torque;
  double         throttle_input;
  double         steering_input;
  double         braking_input;

  // Number of simulation steps between two 3D view render frames
  int render_steps = (int)std::ceil(render_step_size / step_size);

  // Number of simulation steps between two output frames
  int output_steps = (int)std::ceil(output_step_size / step_size);

  // Initialize simulation frame counter and simulation time
  int step_number = 0;
  double time = 0;

#ifdef USE_IRRLICHT

  ChRealtimeStepTimer realtime_timer;

  while (application.GetDevice()->run())
  {
    // update the position of the shadow mapping so that it follows the car
    if (do_shadows)
    {
      ChVector<> lightaim = vehicle.GetChassisPos();
      ChVector<> lightpos = vehicle.GetChassisPos() + ChVector<>(10, 30, 60);
      irr::core::vector3df mlightpos((irr::f32)lightpos.x, (irr::f32)lightpos.y, (irr::f32)lightpos.z);
      irr::core::vector3df mlightaim((irr::f32)lightaim.x, (irr::f32)lightaim.y, (irr::f32)lightaim.z);
      application.GetEffects()->getShadowLight(0).setPosition(mlightpos);
      application.GetEffects()->getShadowLight(0).setTarget(mlightaim);
      mlight->setPosition(mlightpos);
    }

    // Render scene
    if (step_number % render_steps == 0) {
      application.GetVideoDriver()->beginScene(true, true, irr::video::SColor(255, 140, 161, 192));
      driver.DrawAll();
      application.GetVideoDriver()->endScene();
    }

    // Collect output data from modules (for inter-module communication)
    throttle_input = driver.GetThrottle();
    steering_input = driver.GetSteering();
    braking_input = driver.GetBraking();
    powertrain_torque = powertrain.GetOutputTorque();
    driveshaft_speed = vehicle.GetDriveshaftSpeed();
    for (int i = 0; i < num_wheels; i++) {
      tire_forces[i] = tires[i]->GetTireForce();
      wheel_states[i] = vehicle.GetWheelState(i);
    }

    // Update modules (process inputs from other modules)
    time = vehicle.GetChTime();
    driver.Update(time);
    powertrain.Update(time, throttle_input, driveshaft_speed);
    vehicle.Update(time, steering_input, braking_input, powertrain_torque, tire_forces);
    terrain.Update(time);
    for (int i = 0; i < num_wheels; i++)
      tires[i]->Update(time, wheel_states[i]);

    // Advance simulation for one timestep for all modules
    double step = realtime_timer.SuggestSimulationStep(step_size);
    driver.Advance(step);
    powertrain.Advance(step);
    vehicle.Advance(step);
    terrain.Advance(step);
    for (int i = 0; i < num_wheels; i++)
      tires[i]->Advance(step);

    // Increment frame number
    step_number++;
  }

  application.GetDevice()->drop();

#else

  int render_frame = 0;

  if(ChFileutils::MakeDirectory(out_dir.c_str()) < 0) {
    std::cout << "Error creating directory " << out_dir << std::endl;
    return 1;
  }
  if(ChFileutils::MakeDirectory(pov_dir.c_str()) < 0) {
    std::cout << "Error creating directory " << pov_dir << std::endl;
    return 1;
  }

  vehicle.ExportMeshPovray(out_dir);

  char filename[100];

  while (time < tend)
  {
    if (step_number % render_steps == 0) {
      // Output render data
      sprintf(filename, "%s/data_%03d.dat", pov_dir.c_str(), render_frame + 1);
      utils::WriteShapesPovray(&vehicle, filename);
      std::cout << "Output frame:   " << render_frame << std::endl;
      std::cout << "Sim frame:      " << step_number << std::endl;
      std::cout << "Time:           " << time << std::endl;
      std::cout << "   throttle: " << driver.GetThrottle()
                << "   steering: " << driver.GetSteering()
                << "   braking:  " << driver.GetBraking() << std::endl;
      std::cout << std::endl;
      render_frame++;
    }

    // Collect output data from modules (for inter-module communication)
    throttle_input = driver.GetThrottle();
    steering_input = driver.GetSteering();
    braking_input = driver.GetBraking();
    powertrain_torque = powertrain.GetOutputTorque();
    driveshaft_speed = vehicle.GetDriveshaftSpeed();
    for (int i = 0; i < num_wheels; i++) {
      tire_forces[i] = tires[i]->GetTireForce();
      wheel_states[i] = vehicle.GetWheelState(i);
    }

    // Update modules (process inputs from other modules)
    time = vehicle.GetChTime();
    driver.Update(time);
    powertrain.Update(time, throttle_input, driveshaft_speed);
    vehicle.Update(time, steering_input, braking_input, powertrain_torque, tire_forces);
    terrain.Update(time);
    for (int i = 0; i < num_wheels; i++)
      tires[i]->Update(time, wheel_states[i]);

    // Update modules (process inputs from other modules)
    time = vehicle.GetChTime();
    driver.Update(time);
    powertrain.Update(time, throttle_input, driveshaft_speed);
    vehicle.Update(time, steering_input, braking_input, powertrain_torque, tire_forces);
    terrain.Update(time);
    for (int i = 0; i < num_wheels; i++)
      tires[i]->Update(time, wheel_states[i]);

    // Advance simulation for one timestep for all modules
    driver.Advance(step_size);
    powertrain.Advance(step_size);
    vehicle.Advance(step_size);
    terrain.Advance(step_size);
    for (int i = 0; i < num_wheels; i++)
      tires[i]->Advance(step_size);

    // Increment frame number
    step_number++;
  }

#endif

  return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <algorithm>

#include "types.h"

namespace bpftrace {

std::ostream &operator<<(std::ostream &os, Type type)
{
  os << typestr(type);
  return os;
}

std::ostream &operator<<(std::ostream &os, const SizedType &type)
{
  if (type.type == Type::cast)
  {
    os << type.cast_type;
  }
  else if (type.type == Type::integer)
  {
    os << (type.is_signed ? "" : "unsigned ") << "int" << 8*type.size;
  }
  else
  {
    os << type.type;
  }

  if (type.is_pointer)
    os << "*";

  return os;
}

bool SizedType::IsEqual(const SizedType &t) const
{
  return type == t.type && size == t.size && is_signed == t.is_signed;
}

bool SizedType::operator!=(const SizedType &t) const
{
  return !IsEqual(t);
}

bool SizedType::operator==(const SizedType &t) const
{
  return IsEqual(t);
}

bool SizedType::IsArray() const
{
  return type == Type::array || type == Type::string ||
         type == Type::usym  || type == Type::inet ||
         (type == Type::cast && !is_pointer);
}

bool SizedType::IsStack() const
{
  return type == Type::ustack || type == Type::kstack;
}

std::string typestr(Type t)
{
  switch (t)
  {
    case Type::none:     return "none";     break;
    case Type::integer:  return "integer";  break;
    case Type::hist:     return "hist";     break;
    case Type::lhist:    return "lhist";    break;
    case Type::count:    return "count";    break;
    case Type::sum:      return "sum";      break;
    case Type::min:      return "min";      break;
    case Type::max:      return "max";      break;
    case Type::avg:      return "avg";      break;
    case Type::stats:    return "stats";    break;
    case Type::kstack:   return "kstack";   break;
    case Type::ustack:   return "ustack";   break;
    case Type::string:   return "string";   break;
    case Type::ksym:     return "ksym";     break;
    case Type::usym:     return "usym";     break;
    case Type::cast:     return "cast";     break;
    case Type::join:     return "join";     break;
    case Type::probe:    return "probe";    break;
    case Type::username: return "username"; break;
    case Type::inet:     return "inet";     break;
    case Type::stack_mode:return "stack mode";break;
    case Type::array:    return "array";    break;
    default:
      std::cerr << "call or probe type not found" << std::endl;
      abort();
  }
}

ProbeType probetype(const std::string &probeName)
{
  ProbeType retType = ProbeType::invalid;

  auto v = std::find_if(PROBE_LIST.begin(), PROBE_LIST.end(),
                          [&probeName] (const ProbeItem& p) {
                            return (p.name == probeName ||
                                   p.abbr == probeName);
                         });

  if (v != PROBE_LIST.end())
    retType =  v->type;

  return retType;
}

std::string probetypeName(const std::string &probeName)
{
  std::string res = probeName;

  auto v = std::find_if(PROBE_LIST.begin(), PROBE_LIST.end(),
                          [&probeName] (const ProbeItem& p) {
                            return (p.name == probeName ||
                                    p.abbr == probeName);
                          });

  if (v != PROBE_LIST.end())
    res = v->name;

  return res;
}

std::string probetypeName(ProbeType t)
{
   switch (t)
  {
    case ProbeType::invalid:     return "invalid";     break;
    case ProbeType::kprobe:      return "kprobe";      break;
    case ProbeType::kretprobe:   return "kretprobe";   break;
    case ProbeType::uprobe:      return "uprobe";      break;
    case ProbeType::uretprobe:   return "uretprobe";   break;
    case ProbeType::usdt:        return "usdt";        break;
    case ProbeType::tracepoint:  return "tracepoint";  break;
    case ProbeType::profile:     return "profile";     break;
    case ProbeType::interval:    return "interval";    break;
    case ProbeType::software:    return "software";    break;
    case ProbeType::hardware:    return "hardware";    break;
    default:
      std::cerr << "probe type not found" << std::endl;
      abort();
  }
}

uint64_t asyncactionint(AsyncAction a)
{
  return (uint64_t)a;
}

} // namespace bpftrace
<commit_msg>Print Type::string and Type::array size information along with type information<commit_after>#include <iostream>
#include <algorithm>

#include "types.h"

namespace bpftrace {

std::ostream &operator<<(std::ostream &os, Type type)
{
  os << typestr(type);
  return os;
}

std::ostream &operator<<(std::ostream &os, const SizedType &type)
{
  if (type.type == Type::cast)
  {
    os << type.cast_type;
  }
  else if (type.type == Type::integer)
  {
    os << (type.is_signed ? "" : "unsigned ") << "int" << 8*type.size;
  }
  else if (type.type == Type::array)
  {
    os << (type.is_signed ? "" : "unsigned ") << "int" << 8 * type.pointee_size;
    os << "[" << type.size << "]";
  }
  else if (type.type == Type::string)
  {
    os << type.type << "[" << type.size << "]";
  }
  else
  {
    os << type.type;
  }

  if (type.is_pointer)
    os << "*";

  return os;
}

bool SizedType::IsEqual(const SizedType &t) const
{
  return type == t.type && size == t.size && is_signed == t.is_signed;
}

bool SizedType::operator!=(const SizedType &t) const
{
  return !IsEqual(t);
}

bool SizedType::operator==(const SizedType &t) const
{
  return IsEqual(t);
}

bool SizedType::IsArray() const
{
  return type == Type::array || type == Type::string ||
         type == Type::usym  || type == Type::inet ||
         (type == Type::cast && !is_pointer);
}

bool SizedType::IsStack() const
{
  return type == Type::ustack || type == Type::kstack;
}

std::string typestr(Type t)
{
  switch (t)
  {
    case Type::none:     return "none";     break;
    case Type::integer:  return "integer";  break;
    case Type::hist:     return "hist";     break;
    case Type::lhist:    return "lhist";    break;
    case Type::count:    return "count";    break;
    case Type::sum:      return "sum";      break;
    case Type::min:      return "min";      break;
    case Type::max:      return "max";      break;
    case Type::avg:      return "avg";      break;
    case Type::stats:    return "stats";    break;
    case Type::kstack:   return "kstack";   break;
    case Type::ustack:   return "ustack";   break;
    case Type::string:   return "string";   break;
    case Type::ksym:     return "ksym";     break;
    case Type::usym:     return "usym";     break;
    case Type::cast:     return "cast";     break;
    case Type::join:     return "join";     break;
    case Type::probe:    return "probe";    break;
    case Type::username: return "username"; break;
    case Type::inet:     return "inet";     break;
    case Type::stack_mode:return "stack mode";break;
    case Type::array:    return "array";    break;
    default:
      std::cerr << "call or probe type not found" << std::endl;
      abort();
  }
}

ProbeType probetype(const std::string &probeName)
{
  ProbeType retType = ProbeType::invalid;

  auto v = std::find_if(PROBE_LIST.begin(), PROBE_LIST.end(),
                          [&probeName] (const ProbeItem& p) {
                            return (p.name == probeName ||
                                   p.abbr == probeName);
                         });

  if (v != PROBE_LIST.end())
    retType =  v->type;

  return retType;
}

std::string probetypeName(const std::string &probeName)
{
  std::string res = probeName;

  auto v = std::find_if(PROBE_LIST.begin(), PROBE_LIST.end(),
                          [&probeName] (const ProbeItem& p) {
                            return (p.name == probeName ||
                                    p.abbr == probeName);
                          });

  if (v != PROBE_LIST.end())
    res = v->name;

  return res;
}

std::string probetypeName(ProbeType t)
{
   switch (t)
  {
    case ProbeType::invalid:     return "invalid";     break;
    case ProbeType::kprobe:      return "kprobe";      break;
    case ProbeType::kretprobe:   return "kretprobe";   break;
    case ProbeType::uprobe:      return "uprobe";      break;
    case ProbeType::uretprobe:   return "uretprobe";   break;
    case ProbeType::usdt:        return "usdt";        break;
    case ProbeType::tracepoint:  return "tracepoint";  break;
    case ProbeType::profile:     return "profile";     break;
    case ProbeType::interval:    return "interval";    break;
    case ProbeType::software:    return "software";    break;
    case ProbeType::hardware:    return "hardware";    break;
    default:
      std::cerr << "probe type not found" << std::endl;
      abort();
  }
}

uint64_t asyncactionint(AsyncAction a)
{
  return (uint64_t)a;
}

} // namespace bpftrace
<|endoftext|>


<commit_before>#include "include/udata.h"
#include <include/udata_accessors.h>
#include <stdio.h>
#include <cstring>

UserData *getDefaultUserData() {
    UserData *udata = new UserData;
    memset(udata, 0, sizeof(*udata));

    return udata;
}

void freeUserData(UserData *udata) {
    if(udata) {
#ifdef AMICI_WITHOUT_MATLAB
        if(qpositivex) delete[] qpositivex;
        if(p) delete[] p;
        if(k) delete[] k;
        if(ts) delete[] ts;
        if(pbar) delete[] pbar;
        if(xbar) delete[] xbar;
        if(idlist) delete[] idlist;
        if(sx0data) delete sx0data;
        if(z2event) delete[] z2event;
#endif
        if(plist) delete[] plist;
        if(h) delete[] h;
        if(tmp_dxdotdp) delete[] tmp_dxdotdp;
        if(w_tmp) delete[] w_tmp;
        if(dwdx_tmp) delete[] dwdx_tmp;
        if(dwdp_tmp) delete[] dwdp_tmp;
        if(M_tmp) delete[] M_tmp;
        if(dfdx_tmp) delete[] dfdx_tmp;
        if(stau_tmp) delete[] stau_tmp;
        if(tmp_J) SparseDestroyMat(tmp_J);

        delete udata;
    }
}

#ifdef AMICI_WITHOUT_MATLAB
void printUserData(UserData *udata) {
    printf("am_qpositivex: %p\n", udata->am_qpositivex);
    printf("am_plist: %p\n", udata->am_plist);
    printf("am_np: %d\n", udata->am_np);
    printf("am_ny: %d\n", udata->am_ny);
    printf("am_nytrue: %d\n", udata->am_nytrue);
    printf("am_nx: %d\n", udata->am_nx);
    printf("am_nxtrue: %d\n", udata->am_nxtrue);
    printf("am_nz: %d\n", udata->am_nz);
    printf("am_nztrue: %d\n", udata->am_nztrue);
    printf("am_ne: %d\n", udata->am_ne);
    printf("am_nt: %d\n", udata->am_nt);
    printf("am_ng: %d\n", udata->am_ng);
    printf("am_nw: %d\n", udata->am_nw);
    printf("am_ndwdx: %d\n", udata->am_ndwdx);
    printf("am_nnz: %d\n", udata->am_nnz);
    printf("am_nmaxevent: %d\n", udata->am_nmaxevent);
    printf("am_pscale: %d\n", (int)udata->am_pscale);
    printf("am_p: %p\n", udata->am_p);
    printf("am_k: %p\n", udata->am_k);
    printf("am_tstart: %e\n", udata->am_tstart);
    printf("am_ts: %p\n", udata->am_ts);
    printf("am_pbar: %p\n", udata->am_pbar);
    printf("am_xbar: %p\n", udata->am_xbar);
    printf("am_idlist: %p\n", udata->am_idlist);
    printf("am_sensi: %d\n", udata->am_sensi);
    printf("am_atol: %e\n", udata->am_atol);
    printf("am_rtol: %e\n", udata->am_rtol);
    printf("am_maxsteps: %d\n", udata->am_maxsteps);
    printf("am_ism: %d\n", udata->am_ism);
    printf("am_sensi_meth: %d\n", udata->am_sensi_meth);
    printf("am_linsol: %d\n", udata->am_linsol);
    printf("am_interpType: %d\n", udata->am_interpType);
    printf("am_lmm: %d\n", udata->am_lmm);
    printf("am_iter: %d\n", udata->am_iter);
    printf("am_stldet: %d\n", udata->am_stldet);
    printf("am_ubw: %d\n", udata->am_ubw);
    printf("am_lbw: %d\n", udata->am_lbw);
    printf("am_x0data: %p\n", udata->am_x0data);
    printf("am_sx0data: %p\n", udata->am_sx0data);
    printf("am_ordering: %d\n", udata->am_ordering);
    printf("am_z2event: %p\n", udata->am_z2event);
    printf("am_h: %p\n", udata->am_h);
}
#endif
<commit_msg>Fix delete<commit_after>#include "include/udata.h"
#include <include/udata_accessors.h>
#include <stdio.h>
#include <cstring>

UserData *getDefaultUserData() {
    UserData *udata = new UserData;
    memset(udata, 0, sizeof(*udata));

    return udata;
}

void freeUserData(UserData *udata) {
    if(udata) {
#ifdef AMICI_WITHOUT_MATLAB
        if(qpositivex) delete[] qpositivex;
        if(p) delete[] p;
        if(k) delete[] k;
        if(ts) delete[] ts;
        if(pbar) delete[] pbar;
        if(xbar) delete[] xbar;
        if(idlist) delete[] idlist;
        if(x0data) delete[] x0data;
        if(sx0data) delete[] sx0data;
        if(z2event) delete[] z2event;
#endif
        if(plist) delete[] plist;
        if(h) delete[] h;
        if(tmp_dxdotdp) delete[] tmp_dxdotdp;
        if(w_tmp) delete[] w_tmp;
        if(dwdx_tmp) delete[] dwdx_tmp;
        if(dwdp_tmp) delete[] dwdp_tmp;
        if(M_tmp) delete[] M_tmp;
        if(dfdx_tmp) delete[] dfdx_tmp;
        if(stau_tmp) delete[] stau_tmp;
        if(tmp_J) SparseDestroyMat(tmp_J);

        delete udata;
    }
}

#ifdef AMICI_WITHOUT_MATLAB
void printUserData(UserData *udata) {
    printf("am_qpositivex: %p\n", udata->am_qpositivex);
    printf("am_plist: %p\n", udata->am_plist);
    printf("am_np: %d\n", udata->am_np);
    printf("am_ny: %d\n", udata->am_ny);
    printf("am_nytrue: %d\n", udata->am_nytrue);
    printf("am_nx: %d\n", udata->am_nx);
    printf("am_nxtrue: %d\n", udata->am_nxtrue);
    printf("am_nz: %d\n", udata->am_nz);
    printf("am_nztrue: %d\n", udata->am_nztrue);
    printf("am_ne: %d\n", udata->am_ne);
    printf("am_nt: %d\n", udata->am_nt);
    printf("am_ng: %d\n", udata->am_ng);
    printf("am_nw: %d\n", udata->am_nw);
    printf("am_ndwdx: %d\n", udata->am_ndwdx);
    printf("am_nnz: %d\n", udata->am_nnz);
    printf("am_nmaxevent: %d\n", udata->am_nmaxevent);
    printf("am_pscale: %d\n", (int)udata->am_pscale);
    printf("am_p: %p\n", udata->am_p);
    printf("am_k: %p\n", udata->am_k);
    printf("am_tstart: %e\n", udata->am_tstart);
    printf("am_ts: %p\n", udata->am_ts);
    printf("am_pbar: %p\n", udata->am_pbar);
    printf("am_xbar: %p\n", udata->am_xbar);
    printf("am_idlist: %p\n", udata->am_idlist);
    printf("am_sensi: %d\n", udata->am_sensi);
    printf("am_atol: %e\n", udata->am_atol);
    printf("am_rtol: %e\n", udata->am_rtol);
    printf("am_maxsteps: %d\n", udata->am_maxsteps);
    printf("am_ism: %d\n", udata->am_ism);
    printf("am_sensi_meth: %d\n", udata->am_sensi_meth);
    printf("am_linsol: %d\n", udata->am_linsol);
    printf("am_interpType: %d\n", udata->am_interpType);
    printf("am_lmm: %d\n", udata->am_lmm);
    printf("am_iter: %d\n", udata->am_iter);
    printf("am_stldet: %d\n", udata->am_stldet);
    printf("am_ubw: %d\n", udata->am_ubw);
    printf("am_lbw: %d\n", udata->am_lbw);
    printf("am_x0data: %p\n", udata->am_x0data);
    printf("am_sx0data: %p\n", udata->am_sx0data);
    printf("am_ordering: %d\n", udata->am_ordering);
    printf("am_z2event: %p\n", udata->am_z2event);
    printf("am_h: %p\n", udata->am_h);
}
#endif
<|endoftext|>


<commit_before>/*-
 * Copyright 2017 Shivansh Rai
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD$
 */

#include <array>
#include <cstdlib>
#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <unistd.h>

#include "utils.h"
#include "logging.h"

#define READ 0  	/* Pipe descriptor: read end. */
#define WRITE 1 	/* Pipe descriptor: write end. */
#define BUFSIZE 128 	/* Buffer size (used for buffering output
			 * from a utility's execution).
			 */
#define TIMEOUT 2 	/* threshold (seconds) for a function call to return. */

/*
 * Insert a list of user-defined option definitions
 * into a hashmap. These specific option definitions
 * are the ones which one can be easily tested.
 */
void
utils::OptDefinition::InsertOpts()
{
	/* Option definitions. */
	OptRelation h_def;        /* '-h' */
	h_def.type    = 's';
	h_def.value   = "h";
	h_def.keyword = "help";

	OptRelation v_def;        /* '-v' */
	v_def.type    = 's';
	v_def.value   = "v";
	v_def.keyword = "version";

	/*
	 * "opt_map" contains all the options
	 * which can be easily tested.
	 */
	opt_map.insert(std::make_pair<std::string, OptRelation>
		      ("h", (OptRelation)h_def));
	opt_map.insert(std::make_pair<std::string, OptRelation>
		      ("v", (OptRelation)v_def));
};

/*
 * For the utility under test, find the supported options
 * present in the hashmap generated by InsertOpts()
 * and return them in a form of list of option relations.
 */
std::list<utils::OptRelation *>
utils::OptDefinition::CheckOpts(std::string utility)
{
	std::string line;                       /* An individual line in a man-page. */
	std::string opt_name;                   /* Name of the option. */
	std::string opt_identifier = ".It Fl";  /* Identifier for an option in man page. */
	std::string buffer;                     /* Option description extracted from man-page. */
	std::string opt_string;                 /* Identified option names. */
	int opt_position;                       /* Starting index of the (identified) option. */
	int space_index;                        /* First occurrence of space character
					         * in a multi-word option definition.
					         */
	std::list<OptRelation *> identified_opt_list;  /* List of identified option relations. */
	std::list<std::string> supported_sections = { "1", "8" };

	/* Generate the hashmap opt_map. */
	InsertOpts();

	for (const auto &section : supported_sections) {
		std::ifstream infile("groff/" + utility + "." + section);

		/*
		 * Search for all the options accepted by the
		 * utility and collect those present in "opt_map".
		 */
		while (std::getline(infile, line)) {
			if ((opt_position = line.find(opt_identifier)) != std::string::npos) {
				/* Locate the position of option name. */
				opt_position += opt_identifier.length() + 1;

				if (opt_position > line.length()) {
					/*
					 * This condition will trigger when a utility
					 * supports an empty argument, e.g. tset(issue #9)
					 */
					continue;
				}

				/*
				 * Check for long options ; While here, also sanitize
				 * multi-word option definitions in a man page to properly
				 * extract short options from option definitions such as:
				 * 	.It Fl r Ar seconds (taken from date(1)).
				 */
				if ((space_index = line.find(" ", opt_position + 1, 1))
						!= std::string::npos)
					opt_name = line.substr(opt_position, space_index - opt_position);
				else
					opt_name = line.substr(opt_position);

				/*
				 * Check if the identified option matches the identifier.
				 * "opt_list.back()" is the previously checked option, the
				 * description of which is now stored in "buffer".
				 */
				if (!opt_list.empty() &&
						(opt_map_iter = opt_map.find(opt_list.back()))
						!= opt_map.end() &&
						buffer.find((opt_map_iter->second).keyword) != std::string::npos) {
					identified_opt_list.push_back(&(opt_map_iter->second));

					/*
					 * Since the usage of the option under test
					 * is known, we remove it from "opt_list".
					 */
					opt_list.pop_back();
				}

				/* Update the list of valid options. */
				opt_list.push_back(opt_name);

				/* Empty the buffer for next option's description. */
				buffer.clear();
			} else {
				/*
				 * Collect the option description until next
				 * valid option definition is encountered.
				 */
				buffer.append(line);
			}
		}
	}

	return identified_opt_list;
}

/*
 * When pclose() is called on the stream returned by popen(),
 * it waits indefinitely for the created shell process to
 * terminate in cases where the shell command waits for the
 * user input via a blocking read (e.g. passwd(1)).
 * Hence, we define a custom function which alongside
 * returning the read-write file descriptors, also returns
 * the pid of the newly created (child) shell process. This
 * pid can later be used for sending a signal to the child.
 *
 * NOTE For the sake of completeness, we also specify actions
 * to be taken corresponding to the "w" (write) type. However,
 * in this context only the "r" (read) type will be required.
 */

utils::PipeDescriptor*
utils::POpen(const char *command)
{
	int pdes[2];
	char *argv[4];
	pid_t child_pid;
	PipeDescriptor *pipe_descr = (PipeDescriptor *)malloc(sizeof(PipeDescriptor));

	/* Create a pipe with ~
	 *   - pdes[READ]: read end
	 *   - pdes[WRITE]: write end
	 */
	if (pipe2(pdes, O_CLOEXEC) < 0)
		return NULL;

	pipe_descr->readfd = pdes[READ];
	pipe_descr->writefd = pdes[WRITE];

	argv[0] = (char *)"sh"; 	/* Type-cast to avoid compiler warning [-Wwrite-strings]. */
	argv[1] = (char *)"-c";
	argv[2] = (char *)command;
	argv[3] = NULL;

	switch (child_pid = vfork()) {
		case -1: 		/* Error. */
			return NULL;
		case 0: 		/* Child. */
			/*
			 * TODO Verify if the following operations on both read
			 * and write file-descriptors (irrespective of the value
			 * of 'type', which is no longer being used) is safe.
			 */
			if (pdes[WRITE] != STDOUT_FILENO)
				dup2(pdes[WRITE], STDOUT_FILENO);
			else
				fcntl(pdes[WRITE], F_SETFD, 0);
			if (pdes[READ] != STDIN_FILENO)
				dup2(pdes[READ], STDIN_FILENO);
			else
				fcntl(pdes[READ], F_SETFD, 0);

			/*
			 * For current usecase, it might so happen that the child gets
			 * stuck on a blocking read (e.g. passwd(1)) waiting for user
			 * input. In that case the child will be killed via a signal.
			 * To avoid any effect on the parent's execution, we place the
			 * child in a separate process group with pgid set as "child_pid".
			 */
			setpgid(child_pid, child_pid);
			execve("/bin/sh", argv, NULL);
			exit(127);
	}

	pipe_descr->pid = child_pid;

	return pipe_descr;
}

/*
 * Executes the passed argument "command" in a shell
 * and returns its output and the exit status.
 */
std::pair<std::string, int>
utils::Execute(std::string command)
{
	int result;
	std::array<char, BUFSIZE> buffer;
	std::string usage_output;
	struct timeval tv;
	fd_set readfds;
	FILE *pipe;
	PipeDescriptor *pipe_descr;

	DEBUGP("Executing: %s\n", command.c_str());

	pipe_descr = utils::POpen(command.c_str());
	if (pipe_descr == NULL) {
		perror("utils::POpen()");
		exit(EXIT_FAILURE);
	}

	/* Close the unrequired file-descriptor. */
	close(pipe_descr->writefd);

	pipe = fdopen(pipe_descr->readfd, "r");
	free(pipe_descr);
	if (pipe == NULL) {
		close(pipe_descr->readfd);
		perror("fdopen()");
		exit(EXIT_FAILURE);
	}

	/*
	 * Set a timeout value for the spawned shell
	 * process to complete its execution.
	 */
	tv.tv_sec = TIMEOUT;
	tv.tv_usec = 0;

	FD_ZERO(&readfds);
	FD_SET(fileno(pipe), &readfds);
	result = select(fileno(pipe) + 1, &readfds, NULL, NULL, &tv);

	if (result > 0) {
		while (!feof(pipe))
			if (fgets(buffer.data(), BUFSIZE, pipe) != NULL)
				usage_output += buffer.data();
	} else if (result == -1) {
		perror("select()");
		if (kill(pipe_descr->pid, SIGTERM) < 0)
			perror("kill()");
	} else if (result == 0) {
		/*
		 * We gave a relaxed value of 2 seconds for the shell process
		 * to complete it's execution. If at this point it is still
		 * alive, it (most probably) is stuck on a blocking read
		 * waiting for the user input. Since few of the utilities
		 * performing such blocking reads don't respond to SIGINT
		 * (e.g. pax(1)), we terminate the shell process via SIGTERM.
		 */
		if (kill(pipe_descr->pid, SIGTERM) < 0)
			perror("kill()");
	}

	return std::make_pair<std::string, int>
		((std::string)usage_output, WEXITSTATUS(pclose(pipe)));
}
<commit_msg>Update TIMEOUT to 1 second<commit_after>/*-
 * Copyright 2017 Shivansh Rai
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD$
 */

#include <array>
#include <cstdlib>
#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <unistd.h>

#include "utils.h"
#include "logging.h"

#define READ 0  	/* Pipe descriptor: read end. */
#define WRITE 1 	/* Pipe descriptor: write end. */
#define BUFSIZE 128 	/* Buffer size (used for buffering output
			 * from a utility's execution).
			 */
#define TIMEOUT 1 	/* threshold (seconds) for a function call to return. */

/*
 * Insert a list of user-defined option definitions
 * into a hashmap. These specific option definitions
 * are the ones which one can be easily tested.
 */
void
utils::OptDefinition::InsertOpts()
{
	/* Option definitions. */
	OptRelation h_def;        /* '-h' */
	h_def.type    = 's';
	h_def.value   = "h";
	h_def.keyword = "help";

	OptRelation v_def;        /* '-v' */
	v_def.type    = 's';
	v_def.value   = "v";
	v_def.keyword = "version";

	/*
	 * "opt_map" contains all the options
	 * which can be easily tested.
	 */
	opt_map.insert(std::make_pair<std::string, OptRelation>
		      ("h", (OptRelation)h_def));
	opt_map.insert(std::make_pair<std::string, OptRelation>
		      ("v", (OptRelation)v_def));
};

/*
 * For the utility under test, find the supported options
 * present in the hashmap generated by InsertOpts()
 * and return them in a form of list of option relations.
 */
std::list<utils::OptRelation *>
utils::OptDefinition::CheckOpts(std::string utility)
{
	std::string line;                       /* An individual line in a man-page. */
	std::string opt_name;                   /* Name of the option. */
	std::string opt_identifier = ".It Fl";  /* Identifier for an option in man page. */
	std::string buffer;                     /* Option description extracted from man-page. */
	std::string opt_string;                 /* Identified option names. */
	int opt_position;                       /* Starting index of the (identified) option. */
	int space_index;                        /* First occurrence of space character
					         * in a multi-word option definition.
					         */
	std::list<OptRelation *> identified_opt_list;  /* List of identified option relations. */
	std::list<std::string> supported_sections = { "1", "8" };

	/* Generate the hashmap opt_map. */
	InsertOpts();

	for (const auto &section : supported_sections) {
		std::ifstream infile("groff/" + utility + "." + section);

		/*
		 * Search for all the options accepted by the
		 * utility and collect those present in "opt_map".
		 */
		while (std::getline(infile, line)) {
			if ((opt_position = line.find(opt_identifier)) != std::string::npos) {
				/* Locate the position of option name. */
				opt_position += opt_identifier.length() + 1;

				if (opt_position > line.length()) {
					/*
					 * This condition will trigger when a utility
					 * supports an empty argument, e.g. tset(issue #9)
					 */
					continue;
				}

				/*
				 * Check for long options ; While here, also sanitize
				 * multi-word option definitions in a man page to properly
				 * extract short options from option definitions such as:
				 * 	.It Fl r Ar seconds (taken from date(1)).
				 */
				if ((space_index = line.find(" ", opt_position + 1, 1))
						!= std::string::npos)
					opt_name = line.substr(opt_position, space_index - opt_position);
				else
					opt_name = line.substr(opt_position);

				/*
				 * Check if the identified option matches the identifier.
				 * "opt_list.back()" is the previously checked option, the
				 * description of which is now stored in "buffer".
				 */
				if (!opt_list.empty() &&
						(opt_map_iter = opt_map.find(opt_list.back()))
						!= opt_map.end() &&
						buffer.find((opt_map_iter->second).keyword) != std::string::npos) {
					identified_opt_list.push_back(&(opt_map_iter->second));

					/*
					 * Since the usage of the option under test
					 * is known, we remove it from "opt_list".
					 */
					opt_list.pop_back();
				}

				/* Update the list of valid options. */
				opt_list.push_back(opt_name);

				/* Empty the buffer for next option's description. */
				buffer.clear();
			} else {
				/*
				 * Collect the option description until next
				 * valid option definition is encountered.
				 */
				buffer.append(line);
			}
		}
	}

	return identified_opt_list;
}

/*
 * When pclose() is called on the stream returned by popen(),
 * it waits indefinitely for the created shell process to
 * terminate in cases where the shell command waits for the
 * user input via a blocking read (e.g. passwd(1)).
 * Hence, we define a custom function which alongside
 * returning the read-write file descriptors, also returns
 * the pid of the newly created (child) shell process. This
 * pid can later be used for sending a signal to the child.
 *
 * NOTE For the sake of completeness, we also specify actions
 * to be taken corresponding to the "w" (write) type. However,
 * in this context only the "r" (read) type will be required.
 */

utils::PipeDescriptor*
utils::POpen(const char *command)
{
	int pdes[2];
	char *argv[4];
	pid_t child_pid;
	PipeDescriptor *pipe_descr = (PipeDescriptor *)malloc(sizeof(PipeDescriptor));

	/* Create a pipe with ~
	 *   - pdes[READ]: read end
	 *   - pdes[WRITE]: write end
	 */
	if (pipe2(pdes, O_CLOEXEC) < 0)
		return NULL;

	pipe_descr->readfd = pdes[READ];
	pipe_descr->writefd = pdes[WRITE];

	argv[0] = (char *)"sh"; 	/* Type-cast to avoid compiler warning [-Wwrite-strings]. */
	argv[1] = (char *)"-c";
	argv[2] = (char *)command;
	argv[3] = NULL;

	switch (child_pid = vfork()) {
		case -1: 		/* Error. */
			return NULL;
		case 0: 		/* Child. */
			/*
			 * TODO Verify if the following operations on both read
			 * and write file-descriptors (irrespective of the value
			 * of 'type', which is no longer being used) is safe.
			 */
			if (pdes[WRITE] != STDOUT_FILENO)
				dup2(pdes[WRITE], STDOUT_FILENO);
			else
				fcntl(pdes[WRITE], F_SETFD, 0);
			if (pdes[READ] != STDIN_FILENO)
				dup2(pdes[READ], STDIN_FILENO);
			else
				fcntl(pdes[READ], F_SETFD, 0);

			/*
			 * For current usecase, it might so happen that the child gets
			 * stuck on a blocking read (e.g. passwd(1)) waiting for user
			 * input. In that case the child will be killed via a signal.
			 * To avoid any effect on the parent's execution, we place the
			 * child in a separate process group with pgid set as "child_pid".
			 */
			setpgid(child_pid, child_pid);
			execve("/bin/sh", argv, NULL);
			exit(127);
	}

	pipe_descr->pid = child_pid;

	return pipe_descr;
}

/*
 * Executes the passed argument "command" in a shell
 * and returns its output and the exit status.
 */
std::pair<std::string, int>
utils::Execute(std::string command)
{
	int result;
	std::array<char, BUFSIZE> buffer;
	std::string usage_output;
	struct timeval tv;
	fd_set readfds;
	FILE *pipe;
	PipeDescriptor *pipe_descr;

	DEBUGP("Executing: %s\n", command.c_str());

	pipe_descr = utils::POpen(command.c_str());
	if (pipe_descr == NULL) {
		perror("utils::POpen()");
		exit(EXIT_FAILURE);
	}

	/* Close the unrequired file-descriptor. */
	close(pipe_descr->writefd);

	pipe = fdopen(pipe_descr->readfd, "r");
	free(pipe_descr);
	if (pipe == NULL) {
		close(pipe_descr->readfd);
		perror("fdopen()");
		exit(EXIT_FAILURE);
	}

	/*
	 * Set a timeout value for the spawned shell
	 * process to complete its execution.
	 */
	tv.tv_sec = TIMEOUT;
	tv.tv_usec = 0;

	FD_ZERO(&readfds);
	FD_SET(fileno(pipe), &readfds);
	result = select(fileno(pipe) + 1, &readfds, NULL, NULL, &tv);

	if (result > 0) {
		while (!feof(pipe))
			if (fgets(buffer.data(), BUFSIZE, pipe) != NULL)
				usage_output += buffer.data();
	} else if (result == -1) {
		perror("select()");
		if (kill(pipe_descr->pid, SIGTERM) < 0)
			perror("kill()");
	} else if (result == 0) {
		/*
		 * We gave a relaxed value of 2 seconds for the shell process
		 * to complete it's execution. If at this point it is still
		 * alive, it (most probably) is stuck on a blocking read
		 * waiting for the user input. Since few of the utilities
		 * performing such blocking reads don't respond to SIGINT
		 * (e.g. pax(1)), we terminate the shell process via SIGTERM.
		 */
		if (kill(pipe_descr->pid, SIGTERM) < 0)
			perror("kill()");
	}

	return std::make_pair<std::string, int>
		((std::string)usage_output, WEXITSTATUS(pclose(pipe)));
}
<|endoftext|>