<commit_before>// Floating Temple
// Copyright 2015 Derek S. Snyder
//
// 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 "peer/versioned_object_content.h"

#include <map>
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

#include "base/escape.h"
#include "base/linked_ptr.h"
#include "base/logging.h"
#include "base/mutex.h"
#include "base/mutex_lock.h"
#include "base/string_printf.h"
#include "peer/canonical_peer.h"
#include "peer/committed_event.h"
#include "peer/live_object.h"
#include "peer/max_version_map.h"
#include "peer/peer_exclusion_map.h"
#include "peer/peer_thread.h"
#include "peer/proto/transaction_id.pb.h"
#include "peer/sequence_point_impl.h"
#include "peer/shared_object_transaction.h"
#include "peer/shared_object_transaction_info.h"
#include "peer/transaction_id_util.h"
#include "peer/transaction_store_internal_interface.h"

using std::map;
using std::pair;
using std::shared_ptr;
using std::string;
using std::unordered_map;
using std::unordered_set;
using std::vector;

namespace floating_temple {
namespace peer {
namespace {

vector<pair<const CanonicalPeer*, TransactionId>>::const_iterator
FindTransactionIdInVector(
    const vector<pair<const CanonicalPeer*, TransactionId>>& transaction_pairs,
    const TransactionId& transaction_id) {
  const vector<pair<const CanonicalPeer*, TransactionId>>::const_iterator
      end_it = transaction_pairs.end();
  vector<pair<const CanonicalPeer*, TransactionId>>::const_iterator it =
      transaction_pairs.begin();

  while (it != end_it &&
         CompareTransactionIds(it->second, transaction_id) != 0) {
    ++it;
  }

  return it;
}

}  // namespace

VersionedObjectContent::VersionedObjectContent(
    TransactionStoreInternalInterface* transaction_store,
    SharedObject* shared_object)
    : transaction_store_(CHECK_NOTNULL(transaction_store)),
      shared_object_(CHECK_NOTNULL(shared_object)) {
}

VersionedObjectContent::~VersionedObjectContent() {
}

shared_ptr<const LiveObject> VersionedObjectContent::GetWorkingVersion(
    const MaxVersionMap& transaction_store_version_map,
    const SequencePointImpl& sequence_point,
    unordered_map<SharedObject*, PeerObjectImpl*>* new_peer_objects,
    vector<pair<const CanonicalPeer*, TransactionId>>* transactions_to_reject) {
  MutexLock lock(&committed_versions_mu_);

  MaxVersionMap effective_version;
  ComputeEffectiveVersion_Locked(transaction_store_version_map,
                                 &effective_version);

  if (!VersionMapIsLessThanOrEqual(sequence_point.version_map(),
                                   effective_version)) {
    VLOG(1) << "sequence_point.version_map() == "
            << sequence_point.version_map().Dump();
    VLOG(1) << "effective_version == " << effective_version.Dump();

    return shared_ptr<const LiveObject>(nullptr);
  }

  if (CanUseCachedLiveObject_Locked(sequence_point)) {
    CHECK(cached_live_object_.get() != nullptr);
    return cached_live_object_;
  }

  for (;;) {
    PeerThread peer_thread;
    peer_thread.Start(transaction_store_, shared_object_,
                      shared_ptr<LiveObject>(nullptr), new_peer_objects);

    const bool success = ApplyTransactionsToWorkingVersion_Locked(
        &peer_thread, sequence_point, transactions_to_reject);

    peer_thread.Stop();

    if (success) {
      return peer_thread.live_object();
    }
  }

  return shared_ptr<const LiveObject>(nullptr);
}

void VersionedObjectContent::GetTransactions(
    const MaxVersionMap& transaction_store_version_map,
    map<TransactionId, linked_ptr<SharedObjectTransactionInfo>>* transactions,
    MaxVersionMap* effective_version) const {
  CHECK(transactions != nullptr);

  MutexLock lock(&committed_versions_mu_);

  for (const auto& transaction_pair : committed_versions_) {
    const TransactionId& transaction_id = transaction_pair.first;
    const SharedObjectTransaction& transaction = *transaction_pair.second;

    SharedObjectTransactionInfo* const transaction_info =
        new SharedObjectTransactionInfo();

    const vector<linked_ptr<CommittedEvent>>& src_events = transaction.events();
    vector<linked_ptr<CommittedEvent>>* const dest_events =
        &transaction_info->events;
    const vector<linked_ptr<CommittedEvent>>::size_type event_count =
        src_events.size();
    dest_events->resize(event_count);

    for (vector<linked_ptr<CommittedEvent>>::size_type i = 0; i < event_count;
         ++i) {
      (*dest_events)[i].reset(src_events[i]->Clone());
    }

    transaction_info->origin_peer = transaction.origin_peer();

    CHECK(transactions->emplace(transaction_id,
                                make_linked_ptr(transaction_info)).second);
  }

  ComputeEffectiveVersion_Locked(transaction_store_version_map,
                                 effective_version);
}

void VersionedObjectContent::StoreTransactions(
    const CanonicalPeer* origin_peer,
    map<TransactionId, linked_ptr<SharedObjectTransactionInfo>>* transactions,
    const MaxVersionMap& version_map) {
  CHECK(origin_peer != nullptr);
  CHECK(transactions != nullptr);

  MutexLock lock(&committed_versions_mu_);

  for (const auto& transaction_pair : *transactions) {
    const TransactionId& transaction_id = transaction_pair.first;
    SharedObjectTransactionInfo* const transaction_info =
        transaction_pair.second.get();

    CHECK(IsValidTransactionId(transaction_id));
    CHECK(transaction_info != nullptr);

    vector<linked_ptr<CommittedEvent>>* const events =
        &transaction_info->events;
    // TODO(dss): Rename this local variable to distinguish it from the
    // parameter 'origin_peer'.
    const CanonicalPeer* const origin_peer = transaction_info->origin_peer;

    CHECK(origin_peer != nullptr);

    linked_ptr<SharedObjectTransaction>& transaction =
        committed_versions_[transaction_id];

    if (transaction.get() == nullptr) {
      transaction.reset(new SharedObjectTransaction(events, origin_peer));
    }

    // TODO(dss): [BUG] The following statement should use the parameter named
    // 'origin_peer', not the local variable with the same name.
    version_map_.AddPeerTransactionId(origin_peer, transaction_id);
  }

  MaxVersionMap new_version_map;
  GetVersionMapUnion(version_map_, version_map, &new_version_map);
  version_map_.Swap(&new_version_map);

  up_to_date_peers_.insert(origin_peer);
}

void VersionedObjectContent::InsertTransaction(
    const CanonicalPeer* origin_peer, const TransactionId& transaction_id,
    vector<linked_ptr<CommittedEvent>>* events) {
  CHECK(origin_peer != nullptr);
  CHECK(IsValidTransactionId(transaction_id));
  CHECK(events != nullptr);

  MutexLock lock(&committed_versions_mu_);

  linked_ptr<SharedObjectTransaction>& transaction =
      committed_versions_[transaction_id];

  if (transaction.get() == nullptr) {
    transaction.reset(new SharedObjectTransaction(events, origin_peer));
  }

  version_map_.AddPeerTransactionId(origin_peer, transaction_id);
  up_to_date_peers_.insert(origin_peer);
}

void VersionedObjectContent::SetCachedLiveObject(
    const shared_ptr<const LiveObject>& cached_live_object,
    const SequencePointImpl& cached_sequence_point) {
  CHECK(cached_live_object.get() != nullptr);

  MutexLock lock(&committed_versions_mu_);
  cached_live_object_ = cached_live_object;
  cached_sequence_point_.CopyFrom(cached_sequence_point);
}

string VersionedObjectContent::Dump() const {
  MutexLock lock(&committed_versions_mu_);

  string committed_versions_string;
  if (committed_versions_.empty()) {
    committed_versions_string = "{}";
  } else {
    committed_versions_string = "{";

    for (map<TransactionId, linked_ptr<SharedObjectTransaction>>::const_iterator
             it = committed_versions_.begin();
         it != committed_versions_.end(); ++it) {
      if (it != committed_versions_.begin()) {
        committed_versions_string += ",";
      }

      StringAppendF(&committed_versions_string, " \"%s\": %s",
                    TransactionIdToString(it->first).c_str(),
                    it->second->Dump().c_str());
    }

    committed_versions_string += " }";
  }

  string up_to_date_peers_string;
  if (up_to_date_peers_.empty()) {
    up_to_date_peers_string = "[]";
  } else {
    up_to_date_peers_string = "[";

    for (unordered_set<const CanonicalPeer*>::const_iterator it =
             up_to_date_peers_.begin();
         it != up_to_date_peers_.end(); ++it) {
      if (it != up_to_date_peers_.begin()) {
        up_to_date_peers_string += ",";
      }

      StringAppendF(&up_to_date_peers_string, " \"%s\"",
                    CEscape((*it)->peer_id()).c_str());
    }

    up_to_date_peers_string += " ]";
  }

  return StringPrintf(
      "{ \"committed_versions\": %s, \"version_map\": %s, "
      "\"up_to_date_peers\": %s, \"cached_live_object\": %s, "
      "\"cached_sequence_point\": %s }",
      committed_versions_string.c_str(), version_map_.Dump().c_str(),
      up_to_date_peers_string.c_str(), cached_live_object_->Dump().c_str(),
      cached_sequence_point_.Dump().c_str());
}

bool VersionedObjectContent::ApplyTransactionsToWorkingVersion_Locked(
    PeerThread* peer_thread, const SequencePointImpl& sequence_point,
    vector<pair<const CanonicalPeer*, TransactionId>>* transactions_to_reject) {
  CHECK(peer_thread != nullptr);
  CHECK(transactions_to_reject != nullptr);

  for (const auto& transaction_pair : committed_versions_) {
    const TransactionId& transaction_id = transaction_pair.first;
    const SharedObjectTransaction& transaction = *transaction_pair.second;
    const vector<linked_ptr<CommittedEvent>>& events = transaction.events();

    if (!events.empty()) {
      const CanonicalPeer* const origin_peer = transaction.origin_peer();

      if (sequence_point.HasPeerTransactionId(origin_peer, transaction_id) &&
          FindTransactionIdInVector(*transactions_to_reject, transaction_id) ==
              transactions_to_reject->end()) {
        for (const linked_ptr<CommittedEvent>& event : events) {
          peer_thread->QueueEvent(event.get());
        }

        peer_thread->FlushEvents();

        if (peer_thread->conflict_detected()) {
          transactions_to_reject->emplace_back(origin_peer, transaction_id);
          return false;
        }
      }
    }
  }

  return true;
}

void VersionedObjectContent::ComputeEffectiveVersion_Locked(
    const MaxVersionMap& transaction_store_version_map,
    MaxVersionMap* effective_version) const {
  CHECK(effective_version != nullptr);

  const unordered_map<const CanonicalPeer*, TransactionId>&
      version_map_peer_transaction_ids = version_map_.peer_transaction_ids();

  for (const auto& version_map_pair : version_map_peer_transaction_ids) {
    effective_version->AddPeerTransactionId(version_map_pair.first,
                                            version_map_pair.second);
  }

  const unordered_map<const CanonicalPeer*, TransactionId>&
      transaction_store_peer_transaction_ids =
      transaction_store_version_map.peer_transaction_ids();

  for (const CanonicalPeer* const origin_peer : up_to_date_peers_) {
    const unordered_map<const CanonicalPeer*, TransactionId>::const_iterator
        it2 = transaction_store_peer_transaction_ids.find(origin_peer);

    if (it2 != transaction_store_peer_transaction_ids.end()) {
      effective_version->AddPeerTransactionId(origin_peer, it2->second);
    }
  }
}

bool VersionedObjectContent::CanUseCachedLiveObject_Locked(
    const SequencePointImpl& requested_sequence_point) const {
  if (cached_live_object_.get() == nullptr) {
    return false;
  }

  const MaxVersionMap& requested_version_map =
      requested_sequence_point.version_map();
  const MaxVersionMap& cached_version_map =
      cached_sequence_point_.version_map();

  if (!VersionMapIsLessThanOrEqual(cached_version_map, requested_version_map)) {
    return false;
  }

  const unordered_map<const CanonicalPeer*, TransactionId>&
      requested_peer_transactions_ids =
      requested_version_map.peer_transaction_ids();
  const unordered_map<const CanonicalPeer*, TransactionId>&
      cached_peer_transactions_ids = cached_version_map.peer_transaction_ids();

  for (const auto& requested_peer_pair : requested_peer_transactions_ids) {
    const CanonicalPeer* const origin_peer = requested_peer_pair.first;
    const TransactionId& requested_transaction_id = requested_peer_pair.second;

    const unordered_map<const CanonicalPeer*, TransactionId>::const_iterator
        cached_peer_it = cached_peer_transactions_ids.find(origin_peer);

    TransactionId cached_transaction_id;
    if (cached_peer_it == cached_peer_transactions_ids.end()) {
      GetMinTransactionId(&cached_transaction_id);
    } else {
      cached_transaction_id.CopyFrom(cached_peer_it->second);
    }

    const map<TransactionId, linked_ptr<SharedObjectTransaction>>::
        const_iterator start_it = committed_versions_.upper_bound(
        cached_transaction_id);
    const map<TransactionId, linked_ptr<SharedObjectTransaction>>::
        const_iterator end_it = committed_versions_.upper_bound(
        requested_transaction_id);

    for (map<TransactionId, linked_ptr<SharedObjectTransaction>>::const_iterator
             transaction_it = start_it;
         transaction_it != end_it; ++transaction_it) {
      const SharedObjectTransaction& shared_object_transaction =
          *transaction_it->second;

      if (shared_object_transaction.origin_peer() == origin_peer) {
        const vector<linked_ptr<CommittedEvent>>& events =
            shared_object_transaction.events();

        for (const linked_ptr<CommittedEvent>& event : events) {
          const CommittedEvent::Type event_type = event->type();

          if (event_type != CommittedEvent::METHOD_CALL &&
              event_type != CommittedEvent::SUB_METHOD_RETURN) {
            return false;
          }
        }
      }
    }
  }

  if (!PeerExclusionMapsAreEqual(requested_sequence_point.peer_exclusion_map(),
                                 cached_sequence_point_.peer_exclusion_map())) {
    return false;
  }

  if (requested_sequence_point.rejected_peers() !=
      cached_sequence_point_.rejected_peers()) {
    return false;
  }

  return true;
}

}  // namespace peer
}  // namespace floating_temple
<commit_msg>Fix a bug in VersionedObjectContent::Dump() that caused a segfault if cached_live_object_ was null.<commit_after>// Floating Temple
// Copyright 2015 Derek S. Snyder
//
// 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 "peer/versioned_object_content.h"

#include <map>
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

#include "base/escape.h"
#include "base/linked_ptr.h"
#include "base/logging.h"
#include "base/mutex.h"
#include "base/mutex_lock.h"
#include "base/string_printf.h"
#include "peer/canonical_peer.h"
#include "peer/committed_event.h"
#include "peer/live_object.h"
#include "peer/max_version_map.h"
#include "peer/peer_exclusion_map.h"
#include "peer/peer_thread.h"
#include "peer/proto/transaction_id.pb.h"
#include "peer/sequence_point_impl.h"
#include "peer/shared_object_transaction.h"
#include "peer/shared_object_transaction_info.h"
#include "peer/transaction_id_util.h"
#include "peer/transaction_store_internal_interface.h"

using std::map;
using std::pair;
using std::shared_ptr;
using std::string;
using std::unordered_map;
using std::unordered_set;
using std::vector;

namespace floating_temple {
namespace peer {
namespace {

vector<pair<const CanonicalPeer*, TransactionId>>::const_iterator
FindTransactionIdInVector(
    const vector<pair<const CanonicalPeer*, TransactionId>>& transaction_pairs,
    const TransactionId& transaction_id) {
  const vector<pair<const CanonicalPeer*, TransactionId>>::const_iterator
      end_it = transaction_pairs.end();
  vector<pair<const CanonicalPeer*, TransactionId>>::const_iterator it =
      transaction_pairs.begin();

  while (it != end_it &&
         CompareTransactionIds(it->second, transaction_id) != 0) {
    ++it;
  }

  return it;
}

}  // namespace

VersionedObjectContent::VersionedObjectContent(
    TransactionStoreInternalInterface* transaction_store,
    SharedObject* shared_object)
    : transaction_store_(CHECK_NOTNULL(transaction_store)),
      shared_object_(CHECK_NOTNULL(shared_object)) {
}

VersionedObjectContent::~VersionedObjectContent() {
}

shared_ptr<const LiveObject> VersionedObjectContent::GetWorkingVersion(
    const MaxVersionMap& transaction_store_version_map,
    const SequencePointImpl& sequence_point,
    unordered_map<SharedObject*, PeerObjectImpl*>* new_peer_objects,
    vector<pair<const CanonicalPeer*, TransactionId>>* transactions_to_reject) {
  MutexLock lock(&committed_versions_mu_);

  MaxVersionMap effective_version;
  ComputeEffectiveVersion_Locked(transaction_store_version_map,
                                 &effective_version);

  if (!VersionMapIsLessThanOrEqual(sequence_point.version_map(),
                                   effective_version)) {
    VLOG(1) << "sequence_point.version_map() == "
            << sequence_point.version_map().Dump();
    VLOG(1) << "effective_version == " << effective_version.Dump();

    return shared_ptr<const LiveObject>(nullptr);
  }

  if (CanUseCachedLiveObject_Locked(sequence_point)) {
    CHECK(cached_live_object_.get() != nullptr);
    return cached_live_object_;
  }

  for (;;) {
    PeerThread peer_thread;
    peer_thread.Start(transaction_store_, shared_object_,
                      shared_ptr<LiveObject>(nullptr), new_peer_objects);

    const bool success = ApplyTransactionsToWorkingVersion_Locked(
        &peer_thread, sequence_point, transactions_to_reject);

    peer_thread.Stop();

    if (success) {
      return peer_thread.live_object();
    }
  }

  return shared_ptr<const LiveObject>(nullptr);
}

void VersionedObjectContent::GetTransactions(
    const MaxVersionMap& transaction_store_version_map,
    map<TransactionId, linked_ptr<SharedObjectTransactionInfo>>* transactions,
    MaxVersionMap* effective_version) const {
  CHECK(transactions != nullptr);

  MutexLock lock(&committed_versions_mu_);

  for (const auto& transaction_pair : committed_versions_) {
    const TransactionId& transaction_id = transaction_pair.first;
    const SharedObjectTransaction& transaction = *transaction_pair.second;

    SharedObjectTransactionInfo* const transaction_info =
        new SharedObjectTransactionInfo();

    const vector<linked_ptr<CommittedEvent>>& src_events = transaction.events();
    vector<linked_ptr<CommittedEvent>>* const dest_events =
        &transaction_info->events;
    const vector<linked_ptr<CommittedEvent>>::size_type event_count =
        src_events.size();
    dest_events->resize(event_count);

    for (vector<linked_ptr<CommittedEvent>>::size_type i = 0; i < event_count;
         ++i) {
      (*dest_events)[i].reset(src_events[i]->Clone());
    }

    transaction_info->origin_peer = transaction.origin_peer();

    CHECK(transactions->emplace(transaction_id,
                                make_linked_ptr(transaction_info)).second);
  }

  ComputeEffectiveVersion_Locked(transaction_store_version_map,
                                 effective_version);
}

void VersionedObjectContent::StoreTransactions(
    const CanonicalPeer* origin_peer,
    map<TransactionId, linked_ptr<SharedObjectTransactionInfo>>* transactions,
    const MaxVersionMap& version_map) {
  CHECK(origin_peer != nullptr);
  CHECK(transactions != nullptr);

  MutexLock lock(&committed_versions_mu_);

  for (const auto& transaction_pair : *transactions) {
    const TransactionId& transaction_id = transaction_pair.first;
    SharedObjectTransactionInfo* const transaction_info =
        transaction_pair.second.get();

    CHECK(IsValidTransactionId(transaction_id));
    CHECK(transaction_info != nullptr);

    vector<linked_ptr<CommittedEvent>>* const events =
        &transaction_info->events;
    // TODO(dss): Rename this local variable to distinguish it from the
    // parameter 'origin_peer'.
    const CanonicalPeer* const origin_peer = transaction_info->origin_peer;

    CHECK(origin_peer != nullptr);

    linked_ptr<SharedObjectTransaction>& transaction =
        committed_versions_[transaction_id];

    if (transaction.get() == nullptr) {
      transaction.reset(new SharedObjectTransaction(events, origin_peer));
    }

    // TODO(dss): [BUG] The following statement should use the parameter named
    // 'origin_peer', not the local variable with the same name.
    version_map_.AddPeerTransactionId(origin_peer, transaction_id);
  }

  MaxVersionMap new_version_map;
  GetVersionMapUnion(version_map_, version_map, &new_version_map);
  version_map_.Swap(&new_version_map);

  up_to_date_peers_.insert(origin_peer);
}

void VersionedObjectContent::InsertTransaction(
    const CanonicalPeer* origin_peer, const TransactionId& transaction_id,
    vector<linked_ptr<CommittedEvent>>* events) {
  CHECK(origin_peer != nullptr);
  CHECK(IsValidTransactionId(transaction_id));
  CHECK(events != nullptr);

  MutexLock lock(&committed_versions_mu_);

  linked_ptr<SharedObjectTransaction>& transaction =
      committed_versions_[transaction_id];

  if (transaction.get() == nullptr) {
    transaction.reset(new SharedObjectTransaction(events, origin_peer));
  }

  version_map_.AddPeerTransactionId(origin_peer, transaction_id);
  up_to_date_peers_.insert(origin_peer);
}

void VersionedObjectContent::SetCachedLiveObject(
    const shared_ptr<const LiveObject>& cached_live_object,
    const SequencePointImpl& cached_sequence_point) {
  CHECK(cached_live_object.get() != nullptr);

  MutexLock lock(&committed_versions_mu_);
  cached_live_object_ = cached_live_object;
  cached_sequence_point_.CopyFrom(cached_sequence_point);
}

string VersionedObjectContent::Dump() const {
  MutexLock lock(&committed_versions_mu_);

  string committed_versions_string;
  if (committed_versions_.empty()) {
    committed_versions_string = "{}";
  } else {
    committed_versions_string = "{";

    for (map<TransactionId, linked_ptr<SharedObjectTransaction>>::const_iterator
             it = committed_versions_.begin();
         it != committed_versions_.end(); ++it) {
      if (it != committed_versions_.begin()) {
        committed_versions_string += ",";
      }

      StringAppendF(&committed_versions_string, " \"%s\": %s",
                    TransactionIdToString(it->first).c_str(),
                    it->second->Dump().c_str());
    }

    committed_versions_string += " }";
  }

  string up_to_date_peers_string;
  if (up_to_date_peers_.empty()) {
    up_to_date_peers_string = "[]";
  } else {
    up_to_date_peers_string = "[";

    for (unordered_set<const CanonicalPeer*>::const_iterator it =
             up_to_date_peers_.begin();
         it != up_to_date_peers_.end(); ++it) {
      if (it != up_to_date_peers_.begin()) {
        up_to_date_peers_string += ",";
      }

      StringAppendF(&up_to_date_peers_string, " \"%s\"",
                    CEscape((*it)->peer_id()).c_str());
    }

    up_to_date_peers_string += " ]";
  }

  string cached_live_object_string;
  if (cached_live_object_.get() == nullptr) {
    cached_live_object_string = "null";
  } else {
    cached_live_object_string = cached_live_object_->Dump();
  }

  return StringPrintf(
      "{ \"committed_versions\": %s, \"version_map\": %s, "
      "\"up_to_date_peers\": %s, \"cached_live_object\": %s, "
      "\"cached_sequence_point\": %s }",
      committed_versions_string.c_str(), version_map_.Dump().c_str(),
      up_to_date_peers_string.c_str(), cached_live_object_string.c_str(),
      cached_sequence_point_.Dump().c_str());
}

bool VersionedObjectContent::ApplyTransactionsToWorkingVersion_Locked(
    PeerThread* peer_thread, const SequencePointImpl& sequence_point,
    vector<pair<const CanonicalPeer*, TransactionId>>* transactions_to_reject) {
  CHECK(peer_thread != nullptr);
  CHECK(transactions_to_reject != nullptr);

  for (const auto& transaction_pair : committed_versions_) {
    const TransactionId& transaction_id = transaction_pair.first;
    const SharedObjectTransaction& transaction = *transaction_pair.second;
    const vector<linked_ptr<CommittedEvent>>& events = transaction.events();

    if (!events.empty()) {
      const CanonicalPeer* const origin_peer = transaction.origin_peer();

      if (sequence_point.HasPeerTransactionId(origin_peer, transaction_id) &&
          FindTransactionIdInVector(*transactions_to_reject, transaction_id) ==
              transactions_to_reject->end()) {
        for (const linked_ptr<CommittedEvent>& event : events) {
          peer_thread->QueueEvent(event.get());
        }

        peer_thread->FlushEvents();

        if (peer_thread->conflict_detected()) {
          transactions_to_reject->emplace_back(origin_peer, transaction_id);
          return false;
        }
      }
    }
  }

  return true;
}

void VersionedObjectContent::ComputeEffectiveVersion_Locked(
    const MaxVersionMap& transaction_store_version_map,
    MaxVersionMap* effective_version) const {
  CHECK(effective_version != nullptr);

  const unordered_map<const CanonicalPeer*, TransactionId>&
      version_map_peer_transaction_ids = version_map_.peer_transaction_ids();

  for (const auto& version_map_pair : version_map_peer_transaction_ids) {
    effective_version->AddPeerTransactionId(version_map_pair.first,
                                            version_map_pair.second);
  }

  const unordered_map<const CanonicalPeer*, TransactionId>&
      transaction_store_peer_transaction_ids =
      transaction_store_version_map.peer_transaction_ids();

  for (const CanonicalPeer* const origin_peer : up_to_date_peers_) {
    const unordered_map<const CanonicalPeer*, TransactionId>::const_iterator
        it2 = transaction_store_peer_transaction_ids.find(origin_peer);

    if (it2 != transaction_store_peer_transaction_ids.end()) {
      effective_version->AddPeerTransactionId(origin_peer, it2->second);
    }
  }
}

bool VersionedObjectContent::CanUseCachedLiveObject_Locked(
    const SequencePointImpl& requested_sequence_point) const {
  if (cached_live_object_.get() == nullptr) {
    return false;
  }

  const MaxVersionMap& requested_version_map =
      requested_sequence_point.version_map();
  const MaxVersionMap& cached_version_map =
      cached_sequence_point_.version_map();

  if (!VersionMapIsLessThanOrEqual(cached_version_map, requested_version_map)) {
    return false;
  }

  const unordered_map<const CanonicalPeer*, TransactionId>&
      requested_peer_transactions_ids =
      requested_version_map.peer_transaction_ids();
  const unordered_map<const CanonicalPeer*, TransactionId>&
      cached_peer_transactions_ids = cached_version_map.peer_transaction_ids();

  for (const auto& requested_peer_pair : requested_peer_transactions_ids) {
    const CanonicalPeer* const origin_peer = requested_peer_pair.first;
    const TransactionId& requested_transaction_id = requested_peer_pair.second;

    const unordered_map<const CanonicalPeer*, TransactionId>::const_iterator
        cached_peer_it = cached_peer_transactions_ids.find(origin_peer);

    TransactionId cached_transaction_id;
    if (cached_peer_it == cached_peer_transactions_ids.end()) {
      GetMinTransactionId(&cached_transaction_id);
    } else {
      cached_transaction_id.CopyFrom(cached_peer_it->second);
    }

    const map<TransactionId, linked_ptr<SharedObjectTransaction>>::
        const_iterator start_it = committed_versions_.upper_bound(
        cached_transaction_id);
    const map<TransactionId, linked_ptr<SharedObjectTransaction>>::
        const_iterator end_it = committed_versions_.upper_bound(
        requested_transaction_id);

    for (map<TransactionId, linked_ptr<SharedObjectTransaction>>::const_iterator
             transaction_it = start_it;
         transaction_it != end_it; ++transaction_it) {
      const SharedObjectTransaction& shared_object_transaction =
          *transaction_it->second;

      if (shared_object_transaction.origin_peer() == origin_peer) {
        const vector<linked_ptr<CommittedEvent>>& events =
            shared_object_transaction.events();

        for (const linked_ptr<CommittedEvent>& event : events) {
          const CommittedEvent::Type event_type = event->type();

          if (event_type != CommittedEvent::METHOD_CALL &&
              event_type != CommittedEvent::SUB_METHOD_RETURN) {
            return false;
          }
        }
      }
    }
  }

  if (!PeerExclusionMapsAreEqual(requested_sequence_point.peer_exclusion_map(),
                                 cached_sequence_point_.peer_exclusion_map())) {
    return false;
  }

  if (requested_sequence_point.rejected_peers() !=
      cached_sequence_point_.rejected_peers()) {
    return false;
  }

  return true;
}

}  // namespace peer
}  // namespace floating_temple
<|endoftext|>


<commit_before>//#define BLYNK_DEBUG
#define BLYNK_PRINT Serial

#include <wifi_config.h>
#include <blynk_config.h>

#include <BlynkSimpleEsp8266.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <SimpleTimer.h>

//*******************************
//Define variable for Virtual Pins
//********************************
long v0_masterswitch = 0;
long v1_sleepinterval = 30;
//Default start at 6 am
int v2_irrigation_min_starttime = 6 * 3600;
//Default stop at 7 pm
int v2_irrigation_max_endtime = 19 * 3600;

//V3 has no matching variable on purpose. Its a display text generated via value of V4

int v4_irrigation_last_dose =  0;
int v5_irrigation_dosage_volume = 15;
int v6_irrigation_dosage_interval = 2 * 3600;
int v7_override =0;

//*******************************
//Define other variables
//********************************
bool pump_running = false;
WiFiUDP Udp;
NTPClient ntpclient(Udp);
bool isFirstConnect = true;
SimpleTimer timer_sleep_esp;
SimpleTimer timer_do_work;
SimpleTimer timer_stop_pump;

//*******************************
//Define Constants
//********************************

//Difference in seconds between Local time zone and UTC.
//Use positive for East of 0 deg longitude and Negative for West of 0 deg longitude
const int TIMEZONE_OFFSET = ((5*60) +30) * 60;
const uint PUMP_PIN = 4;

//Declare Function signature to avoid having the body before the call
void dowork();

void sleep_timerfunc_interval()
{

  BLYNK_LOG("Inside sleep_timerfunc_interval");

  //Don't deep sleep if pump is running.
  if (pump_running)
  {
    BLYNK_LOG("Pump is running");
    return;
  }

  BLYNK_LOG("Starting to Sleep for %d minutes", v1_sleepinterval);
  ESP.deepSleep(60 * v1_sleepinterval * 1000000,RF_DEFAULT);
  delay(1000);
}

void timerfunc_timeout_stop_pump()
{
  //ESP.deepSleep(v1_sleepinterval * 60* 1000000,RF_DEFAULT);
  BLYNK_LOG("Stopping the Pump");
  pump_running = false;
  digitalWrite(PUMP_PIN,LOW);
}

BLYNK_CONNECTED() {
  BLYNK_LOG("In BLYNK_CONNECTED");
  if (isFirstConnect){
    Blynk.syncAll();
    isFirstConnect = false;
    BLYNK_LOG("Synced via BLYNK_CONNECTED");
  }
}

BLYNK_WRITE(V0) // There is a Widget that WRITEs data to V0
{
   v0_masterswitch = param.asInt();
   BLYNK_LOG("Change Master Switch is %d" , param.asInt());
}

BLYNK_WRITE(V1) // There is a Widget that WRITEs data to V1
{
   v1_sleepinterval = param.asInt();
   BLYNK_LOG("Change Sleep Interval is %d" , param.asInt());
}

BLYNK_WRITE(V2) // There is a Widget that WRITEs data to V2
{

  TimeInputParam t(param);
  v2_irrigation_min_starttime = param[0].asInt();
  v2_irrigation_max_endtime = param[1].asInt();

  BLYNK_LOG ("Irrigation Start Time %d",v2_irrigation_min_starttime);
  BLYNK_LOG ("Irrigation Stop Time %d",v2_irrigation_max_endtime);
}

BLYNK_WRITE(V3) // There is a Widget that WRITEs data to V3
{
  BLYNK_LOG ("V3 is just a display text. It has no variable in h/w");
}

BLYNK_WRITE(V4) // There is a Widget that WRITEs data to V4
{
  v4_irrigation_last_dose = param.asInt();

  BLYNK_LOG ("Change Last watering time is %d",v4_irrigation_last_dose);
}

BLYNK_WRITE(V5) // There is a Widget that WRITEs data to V4
{
  v5_irrigation_dosage_volume = param.asInt();
  BLYNK_LOG ("Change Time for watering is %d seconds",v5_irrigation_dosage_volume);
}

BLYNK_WRITE(V6) // There is a Widget that WRITEs data to V6
{
  v6_irrigation_dosage_interval = param.asInt();
  BLYNK_LOG ("Change Delta between consecutive watering cycles is %d hours",v6_irrigation_dosage_interval);
}

BLYNK_WRITE(V7) // There is a Widget that WRITEs data to V4
{
  v7_override = param.asInt();
  BLYNK_LOG ("Change Override Switch %d",v7_override);
}

void setup(/* arguments */) {
  /* code */
  Serial.begin(115200);

  BLYNK_LOG("In setup");

  pinMode(PUMP_PIN,OUTPUT);
  digitalWrite(PUMP_PIN, LOW);
  Blynk.begin(BLYNK_AUTH,WIFI_SSID,WIFI_PASSWORD);

  BLYNK_LOG("Waiting for BLYNK Server");

  while (! Blynk.connected())
  {
    BLYNK_LOG(".");
  }

  ntpclient.setTimeOffset(TIMEZONE_OFFSET);
  ntpclient.begin();
  ntpclient.update();

  BLYNK_LOG("Starting timer");
  timer_sleep_esp.setInterval(30000L, sleep_timerfunc_interval);
  timer_do_work.setTimeout(10000L, dowork);
}

void loop(/* arguments */) {
  /* code */

  //TODO
  /*  Put code here to check for wifi and internet connectivity.
  Deep sleep for a long time if check fails to avoid battery wastage */
  timer_sleep_esp.run();
  Blynk.run();
  timer_do_work.run();

  if (pump_running)
  {
    timer_stop_pump.run();
  }
}

void dowork()
{
  BLYNK_LOG ("In dowork");
  long now = ntpclient.getEpochTime();

  //Check if we need to start the pump
  //get seconds from start of the day
  long seconds_since_start_of_day = (ntpclient.getHours() * 3600) +  (ntpclient.getMinutes() * 60 ) +  ntpclient.getSeconds();

  BLYNK_LOG ("Last watering time is %d",v4_irrigation_last_dose);
  BLYNK_LOG ("Time between consecutive cycles %d",v6_irrigation_dosage_interval);

  BLYNK_LOG ("Seconds since start of day %d",seconds_since_start_of_day);
  if (v0_masterswitch == HIGH)
  {
    BLYNK_LOG ("Override is %d", v7_override);
    if (  v7_override or (  seconds_since_start_of_day >= (v4_irrigation_last_dose + v6_irrigation_dosage_interval)))
    {

      BLYNK_LOG ("Watering needed based on last dose and interval");
      if (v7_override or ( ( seconds_since_start_of_day >= v2_irrigation_min_starttime ) and (seconds_since_start_of_day <= v2_irrigation_max_endtime)))
      {
          //BLYNK_LOG ("Current time is within min and max time window");
          BLYNK_LOG ("Watering conditions met. Waterning now.");
          //All Conditions met.
          pump_running = true;
          digitalWrite(PUMP_PIN, HIGH);

          //Set the last watering time to current time to avoid this getting triggered again till the next cycle
          Blynk.virtualWrite(V4, seconds_since_start_of_day);

          v4_irrigation_last_dose = seconds_since_start_of_day;
          //Blynk.virtualWrite(V4, String(v4_irrigation_last_dose).c_str());
          Blynk.virtualWrite(V4, v4_irrigation_last_dose);

          //Create a buffer to hold string HH:MM:SS
          char v3_display_buffer[10];
          sprintf(v3_display_buffer, " %2d:%2d:%2d",ntpclient.getHours(), ntpclient.getMinutes() ,ntpclient.getSeconds());
          Blynk.virtualWrite(V3, v3_display_buffer);
          BLYNK_LOG ("Last watering time in text %s",v3_display_buffer);
          timer_stop_pump.setTimeout( v5_irrigation_dosage_volume * 1000, timerfunc_timeout_stop_pump);
      }
    }
  }

  //Reset Override
  if (v7_override)
  {
    Blynk.virtualWrite(V7, 0);
  }
}
<commit_msg>Use epoch for time calculations<commit_after>//#define BLYNK_DEBUG
#define BLYNK_PRINT Serial

#include <wifi_config.h>
#include <blynk_config.h>

#include <BlynkSimpleEsp8266.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <SimpleTimer.h>

//*******************************
//Define variable for Virtual Pins
//********************************
long v0_masterswitch = 0;
long v1_sleepinterval = 30;
//Default start at 6 am
int v2_irrigation_min_starttime = 6 * 3600;
//Default stop at 7 pm
int v2_irrigation_max_endtime = 19 * 3600;

//V3 has no matching variable on purpose. Its a display text generated via value of V4

long v4_irrigation_last_dose =  0L;
int v5_irrigation_dosage_volume = 15;
int v6_irrigation_dosage_interval = 2 * 3600;
int v7_override =0;

//*******************************
//Define other variables
//********************************
bool pump_running = false;
WiFiUDP Udp;
NTPClient ntpclient(Udp);
bool isFirstConnect = true;
SimpleTimer timer_sleep_esp;
SimpleTimer timer_do_work;
SimpleTimer timer_stop_pump;

//*******************************
//Define Constants
//********************************

//Difference in seconds between Local time zone and UTC.
//Use positive for East of 0 deg longitude and Negative for West of 0 deg longitude
const int TIMEZONE_OFFSET = ((5*60) +30) * 60;
const uint PUMP_PIN = 4;

//Declare Function signature to avoid having the body before the call
void dowork();

void sleep_timerfunc_interval()
{

  BLYNK_LOG("Inside sleep_timerfunc_interval");

  //Don't deep sleep if pump is running.
  if (pump_running)
  {
    BLYNK_LOG("Pump is running");
    return;
  }

  BLYNK_LOG("Starting to Sleep for %d minutes", v1_sleepinterval);
  ESP.deepSleep(60 * v1_sleepinterval * 1000000,RF_DEFAULT);
  delay(1000);
}

void timerfunc_timeout_stop_pump()
{
  //ESP.deepSleep(v1_sleepinterval * 60* 1000000,RF_DEFAULT);
  BLYNK_LOG("Stopping the Pump");
  pump_running = false;
  digitalWrite(PUMP_PIN,LOW);
}

BLYNK_CONNECTED() {
  BLYNK_LOG("In BLYNK_CONNECTED");
  if (isFirstConnect){
    Blynk.syncAll();
    isFirstConnect = false;
    BLYNK_LOG("Synced via BLYNK_CONNECTED");
  }
}

BLYNK_WRITE(V0) // There is a Widget that WRITEs data to V0
{
   v0_masterswitch = param.asInt();
   BLYNK_LOG("Change Master Switch is %d" , param.asInt());
}

BLYNK_WRITE(V1) // There is a Widget that WRITEs data to V1
{
   v1_sleepinterval = param.asInt();
   BLYNK_LOG("Change Sleep Interval is %d" , param.asInt());
}

BLYNK_WRITE(V2) // There is a Widget that WRITEs data to V2
{

  TimeInputParam t(param);
  v2_irrigation_min_starttime = param[0].asInt();
  v2_irrigation_max_endtime = param[1].asInt();

  BLYNK_LOG ("Irrigation Start Time %d",v2_irrigation_min_starttime);
  BLYNK_LOG ("Irrigation Stop Time %d",v2_irrigation_max_endtime);
}

BLYNK_WRITE(V3) // There is a Widget that WRITEs data to V3
{
  BLYNK_LOG ("V3 is just a display text. It has no variable in h/w");
}

BLYNK_WRITE(V4) // There is a Widget that WRITEs data to V4
{
  v4_irrigation_last_dose = param.asLong();

  BLYNK_LOG ("Change Last watering time is %ld",v4_irrigation_last_dose);
}

BLYNK_WRITE(V5) // There is a Widget that WRITEs data to V4
{
  v5_irrigation_dosage_volume = param.asInt();
  BLYNK_LOG ("Change Time for watering is %d seconds",v5_irrigation_dosage_volume);
}

BLYNK_WRITE(V6) // There is a Widget that WRITEs data to V6
{
  v6_irrigation_dosage_interval = param.asInt();
  BLYNK_LOG ("Change Delta between consecutive watering cycles is %d hours",v6_irrigation_dosage_interval);
}

BLYNK_WRITE(V7) // There is a Widget that WRITEs data to V4
{
  v7_override = param.asInt();
  BLYNK_LOG ("Change Override Switch %d",v7_override);
}

void setup(/* arguments */) {
  /* code */
  Serial.begin(115200);

  BLYNK_LOG("In setup");

  pinMode(PUMP_PIN,OUTPUT);
  digitalWrite(PUMP_PIN, LOW);
  Blynk.begin(BLYNK_AUTH,WIFI_SSID,WIFI_PASSWORD);

  BLYNK_LOG("Waiting for BLYNK Server");

  while (! Blynk.connected())
  {
    BLYNK_LOG(".");
  }

  ntpclient.setTimeOffset(TIMEZONE_OFFSET);
  ntpclient.begin();
  ntpclient.update();

  BLYNK_LOG("Starting timer");
  timer_sleep_esp.setInterval(30000L, sleep_timerfunc_interval);
  timer_do_work.setTimeout(10000L, dowork);
}

void loop(/* arguments */) {
  /* code */

  //TODO
  /*  Put code here to check for wifi and internet connectivity.
  Deep sleep for a long time if check fails to avoid battery wastage */
  timer_sleep_esp.run();
  Blynk.run();
  timer_do_work.run();

  if (pump_running)
  {
    timer_stop_pump.run();
  }
}

void dowork()
{
  BLYNK_LOG ("In dowork");
  long now = ntpclient.getEpochTime();

  //Check if we need to start the pump
  //get epoch
  long epoch =  ntpclient.getEpochTime();
  //get seconds from start of the day
  int seconds_since_start_of_day = epoch % 86400;

  BLYNK_LOG ("Epoch is %ld",epoch);
  BLYNK_LOG ("Last watering time is %ld",v4_irrigation_last_dose);
  BLYNK_LOG ("Time between consecutive cycles %d",v6_irrigation_dosage_interval);

  BLYNK_LOG ("Seconds since start of day %d",seconds_since_start_of_day);
  if (v0_masterswitch == HIGH)
  {
    BLYNK_LOG ("Override is %d", v7_override);
    if (  v7_override or (  epoch >= (v4_irrigation_last_dose + v6_irrigation_dosage_interval)))
    {

      BLYNK_LOG ("Watering needed based on last dose and interval");
      if (v7_override or ( ( seconds_since_start_of_day >= v2_irrigation_min_starttime ) and (seconds_since_start_of_day <= v2_irrigation_max_endtime)))
      {
          //BLYNK_LOG ("Current time is within min and max time window");
          BLYNK_LOG ("Watering conditions met. Waterning now.");
          //All Conditions met.
          pump_running = true;
          digitalWrite(PUMP_PIN, HIGH);

          //Set the last watering time to current time to avoid this getting triggered again till the next cycle
          v4_irrigation_last_dose = epoch;
          Blynk.virtualWrite(V4, v4_irrigation_last_dose);

          //Create a buffer to hold string HH:MM:SS
          //char v3_display_buffer[10];
          //sprintf(v3_display_buffer, "%02d:%02d:%02d",ntpclient.getHours(), ntpclient.getMinutes() ,ntpclient.getSeconds());
          String v3_display_buffer;
          v3_display_buffer = ntpclient.getFormattedTime();
          Blynk.virtualWrite(V3, v3_display_buffer);

          BLYNK_LOG ("Last watering time in text %s",v3_display_buffer.c_str());
          timer_stop_pump.setTimeout( v5_irrigation_dosage_volume * 1000, timerfunc_timeout_stop_pump);
      }
    }
  }

  //Reset Override
  if (v7_override)
  {
    Blynk.virtualWrite(V7, 0);
  }
}
<|endoftext|>


<commit_before>// ***************************************************************************
// FastaIndex.cpp (c) 2010 Erik Garrison <erik.garrison@bc.edu>
// Marth Lab, Department of Biology, Boston College
// All rights reserved.
// ---------------------------------------------------------------------------
// Last modified: 9 February 2010 (EG)
// ---------------------------------------------------------------------------

#include "Fasta.h"

FastaIndexEntry::FastaIndexEntry(string name, int length, long long offset, int line_blen, int line_len)
    : name(name)
    , length(length)
    , offset(offset)
    , line_blen(line_blen)
    , line_len(line_len)
{}

FastaIndexEntry::FastaIndexEntry(void) // empty constructor
{ clear(); }

FastaIndexEntry::~FastaIndexEntry(void)
{}

void FastaIndexEntry::clear(void)
{
    name = "";
    length = 0;
    offset = -1;  // no real offset will ever be below 0, so this allows us to
                  // check if we have already recorded a real offset
    line_blen = 0;
    line_len = 0;
}

ostream& operator<<(ostream& output, const FastaIndexEntry& e) {
    // just write the first component of the name, for compliance with other tools
    output << split(e.name, ' ').at(0) << "\t" << e.length << "\t" << e.offset << "\t" <<
        e.line_blen << "\t" << e.line_len;
    return output;  // for multiple << operators.
}

FastaIndex::FastaIndex(void)
{}

void FastaIndex::readIndexFile(string fname) {
    string line;
    long long linenum = 0;
    indexFile.open(fname.c_str(), ifstream::in);
    if (indexFile.is_open()) {
        while (getline (indexFile, line)) {
            ++linenum;
            // the fai format defined in samtools is tab-delimited, every line being:
            // fai->name[i], (int)x.len, (long long)x.offset, (int)x.line_blen, (int)x.line_len
            vector<string> fields = split(line, '\t');
            if (fields.size() == 5) {  // if we don't get enough fields then there is a problem with the file
                // note that fields[0] is the sequence name
                char* end;
                string name = split(fields[0], " \t").at(0);  // key by first token of name
                sequenceNames.push_back(name);
                this->insert(make_pair(name, FastaIndexEntry(fields[0], atoi(fields[1].c_str()),
                                                    strtoll(fields[2].c_str(), &end, 10),
                                                    atoi(fields[3].c_str()),
                                                    atoi(fields[4].c_str()))));
            } else {
                cerr << "Warning: malformed fasta index file " << fname <<
                    "does not have enough fields @ line " << linenum << endl;
                cerr << line << endl;
                exit(1);
            }
        }
    } else {
        cerr << "could not open index file " << fname << endl;
        exit(1);
    }
}

// for consistency this should be a class method
bool fastaIndexEntryCompare ( FastaIndexEntry a, FastaIndexEntry b) { return (a.offset<b.offset); }

ostream& operator<<(ostream& output, FastaIndex& fastaIndex) {
    vector<FastaIndexEntry> sortedIndex;
    for(vector<string>::const_iterator it = fastaIndex.sequenceNames.begin(); it != fastaIndex.sequenceNames.end(); ++it)
    {
        sortedIndex.push_back(fastaIndex[*it]);
    }
    sort(sortedIndex.begin(), sortedIndex.end(), fastaIndexEntryCompare);
    for( vector<FastaIndexEntry>::iterator fit = sortedIndex.begin(); fit != sortedIndex.end(); ++fit) {
        output << *fit << endl;
    }
}

void FastaIndex::indexReference(string refname) {
    // overview:
    //  for line in the reference fasta file
    //  track byte offset from the start of the file
    //  if line is a fasta header, take the name and dump the last sequnece to the index
    //  if line is a sequence, add it to the current sequence
    //cerr << "indexing fasta reference " << refname << endl;
    string line;
    FastaIndexEntry entry;  // an entry buffer used in processing
    entry.clear();
    int line_length = 0;
    long long offset = 0;  // byte offset from start of file
    long long line_number = 0; // current line number
    bool mismatchedLineLengths = false; // flag to indicate if our line length changes mid-file
                                        // this will be used to raise an error
                                        // if we have a line length change at
                                        // any line other than the last line in
                                        // the sequence
    bool emptyLine = false;  // flag to catch empty lines, which we allow for
                             // index generation only on the last line of the sequence
    ifstream refFile;
    refFile.open(refname.c_str());
    if (refFile.is_open()) {
        while (getline(refFile, line)) {
            ++line_number;
            line_length = line.length();
            if (line[0] == ';') {
                // fasta comment, skip
            } else if (line[0] == '+') {
                // fastq quality header
                getline(refFile, line);
                line_length = line.length();
                offset += line_length + 1;
                // get and don't handle the quality line
                getline(refFile, line);
                line_length = line.length();
            } else if (line[0] == '>' || line[0] == '@') { // fasta /fastq header
                // if we aren't on the first entry, push the last sequence into the index
                if (entry.name != "") {
                    mismatchedLineLengths = false; // reset line length error tracker for every new sequence
                    emptyLine = false;
                    flushEntryToIndex(entry);
                    entry.clear();
                }
                entry.name = line.substr(1, line_length - 1);
            } else { // we assume we have found a sequence line
                if (entry.offset == -1) // NB initially the offset is -1
                    entry.offset = offset;
                entry.length += line_length;
                if (entry.line_len) {
                    //entry.line_len = entry.line_len ? entry.line_len : line_length + 1;
                    if (mismatchedLineLengths || emptyLine) {
                        if (line_length == 0) {
                            emptyLine = true; // flag empty lines, raise error only if this is embedded in the sequence
                        } else {
                            if (emptyLine) {
                                cerr << "ERROR: embedded newline";
                            } else {
                                cerr << "ERROR: mismatched line lengths";
                            }
                            cerr << " at line " << line_number << " within sequence " << entry.name <<
                                endl << "File not suitable for fasta index generation." << endl;
                            exit(1);
                        }
                    }
                    // this flag is set here and checked on the next line
                    // because we may have reached the end of the sequence, in
                    // which case a mismatched line length is OK
                    if (entry.line_len != line_length + 1) {
                        mismatchedLineLengths = true;
                        if (line_length == 0) {
                            emptyLine = true; // flag empty lines, raise error only if this is embedded in the sequence
                        }
                    }
                } else {
                    entry.line_len = line_length + 1; // first line
                }
                entry.line_blen = entry.line_len - 1;
            }
            offset += line_length + 1;
        }
        // we've hit the end of the fasta file!
        // flush the last entry
        flushEntryToIndex(entry);
    } else {
        cerr << "could not open reference file " << refname << " for indexing!" << endl;
        exit(1);
    }
}

void FastaIndex::flushEntryToIndex(FastaIndexEntry& entry) {
    string name = split(entry.name, " \t").at(0);  // key by first token of name
    sequenceNames.push_back(name);
    this->insert(make_pair(name, FastaIndexEntry(entry.name, entry.length,
                        entry.offset, entry.line_blen,
                        entry.line_len)));

}

void FastaIndex::writeIndexFile(string fname) {
    //cerr << "writing fasta index file " << fname << endl;
    ofstream file;
    file.open(fname.c_str());
    if (file.is_open()) {
        file << *this;
    } else {
        cerr << "could not open index file " << fname << " for writing!" << endl;
        exit(1);
    }
}

FastaIndex::~FastaIndex(void) {
    indexFile.close();
}

FastaIndexEntry FastaIndex::entry(string name) {
    FastaIndex::iterator e = this->find(name);
    if (e == this->end()) {
        cerr << "unable to find FASTA index entry for '" << name << "'" << endl;
        exit(1);
    } else {
        return e->second;
    }
}

string FastaIndex::indexFileExtension() { return ".fai"; }

/*
FastaReference::FastaReference(string reffilename) {
}
*/

void FastaReference::open(string reffilename) {
    filename = reffilename;
    if (!(file = fopen(filename.c_str(), "r"))) {
        cerr << "could not open " << filename << endl;
        exit(1);
    }
    index = new FastaIndex();
    struct stat stFileInfo;
    string indexFileName = filename + index->indexFileExtension();
    // if we can find an index file, use it
    if(stat(indexFileName.c_str(), &stFileInfo) == 0) {
        index->readIndexFile(indexFileName);
    } else { // otherwise, read the reference and generate the index file in the cwd
        cerr << "index file " << indexFileName << " not found, generating..." << endl;
        index->indexReference(filename);
        index->writeIndexFile(indexFileName);
    }
}

FastaReference::~FastaReference(void) {
    fclose(file);
    delete index;
}

string FastaReference::getSequence(string seqname) {
    FastaIndexEntry entry = index->entry(seqname);
    int newlines_in_sequence = entry.length / entry.line_blen;
    int seqlen = newlines_in_sequence  + entry.length;
    char* seq = (char*) calloc (seqlen + 1, sizeof(char));
    fseek64(file, entry.offset, SEEK_SET);
    fread(seq, sizeof(char), seqlen, file);
    seq[seqlen] = '\0';
    char* pbegin = seq;
    char* pend = seq + (seqlen/sizeof(char));
    pend = remove(pbegin, pend, '\n');
    pend = remove(pbegin, pend, '\0');
    string s = seq;
    free(seq);
    s.resize((pend - pbegin)/sizeof(char));
    return s;
}

// TODO cleanup; odd function.  use a map
string FastaReference::sequenceNameStartingWith(string seqnameStart) {
    try {
        return (*index)[seqnameStart].name;
    } catch (exception& e) {
        cerr << e.what() << ": unable to find index entry for " << seqnameStart << endl;
        exit(1);
    }
}

string FastaReference::getSubSequence(string seqname, int start, int length) {
    FastaIndexEntry entry = index->entry(seqname);
    length = min(length, entry.length - start);
    if (start < 0 || length < 1) {
        return "";
    }
    // we have to handle newlines
    // approach: count newlines before start
    //           count newlines by end of read
    //             subtracting newlines before start find count of embedded newlines
    int newlines_before = start > 0 ? (start - 1) / entry.line_blen : 0;
    int newlines_by_end = (start + length - 1) / entry.line_blen;
    int newlines_inside = newlines_by_end - newlines_before;
    int seqlen = length + newlines_inside;
    char* seq = (char*) calloc (seqlen + 1, sizeof(char));
    fseek64(file, (off_t) (entry.offset + newlines_before + start), SEEK_SET);
    fread(seq, sizeof(char), (off_t) seqlen, file);
    seq[seqlen] = '\0';
    char* pbegin = seq;
    char* pend = seq + (seqlen/sizeof(char));
    pend = remove(pbegin, pend, '\n');
    pend = remove(pbegin, pend, '\0');
    string s = seq;
    free(seq);
    s.resize((pend - pbegin)/sizeof(char));
    return s;
}

long unsigned int FastaReference::sequenceLength(string seqname) {
    FastaIndexEntry entry = index->entry(seqname);
    return entry.length;
}

<commit_msg>VCF's should not include IUPAC bases in the REF column.<commit_after>// ***************************************************************************
// FastaIndex.cpp (c) 2010 Erik Garrison <erik.garrison@bc.edu>
// Marth Lab, Department of Biology, Boston College
// All rights reserved.
// ---------------------------------------------------------------------------
// Last modified: 9 February 2010 (EG)
// ---------------------------------------------------------------------------

#include "Fasta.h"

FastaIndexEntry::FastaIndexEntry(string name, int length, long long offset, int line_blen, int line_len)
    : name(name)
    , length(length)
    , offset(offset)
    , line_blen(line_blen)
    , line_len(line_len)
{}

FastaIndexEntry::FastaIndexEntry(void) // empty constructor
{ clear(); }

FastaIndexEntry::~FastaIndexEntry(void)
{}

void FastaIndexEntry::clear(void)
{
    name = "";
    length = 0;
    offset = -1;  // no real offset will ever be below 0, so this allows us to
                  // check if we have already recorded a real offset
    line_blen = 0;
    line_len = 0;
}

ostream& operator<<(ostream& output, const FastaIndexEntry& e) {
    // just write the first component of the name, for compliance with other tools
    output << split(e.name, ' ').at(0) << "\t" << e.length << "\t" << e.offset << "\t" <<
        e.line_blen << "\t" << e.line_len;
    return output;  // for multiple << operators.
}

FastaIndex::FastaIndex(void)
{}

void FastaIndex::readIndexFile(string fname) {
    string line;
    long long linenum = 0;
    indexFile.open(fname.c_str(), ifstream::in);
    if (indexFile.is_open()) {
        while (getline (indexFile, line)) {
            ++linenum;
            // the fai format defined in samtools is tab-delimited, every line being:
            // fai->name[i], (int)x.len, (long long)x.offset, (int)x.line_blen, (int)x.line_len
            vector<string> fields = split(line, '\t');
            if (fields.size() == 5) {  // if we don't get enough fields then there is a problem with the file
                // note that fields[0] is the sequence name
                char* end;
                string name = split(fields[0], " \t").at(0);  // key by first token of name
                sequenceNames.push_back(name);
                this->insert(make_pair(name, FastaIndexEntry(fields[0], atoi(fields[1].c_str()),
                                                    strtoll(fields[2].c_str(), &end, 10),
                                                    atoi(fields[3].c_str()),
                                                    atoi(fields[4].c_str()))));
            } else {
                cerr << "Warning: malformed fasta index file " << fname <<
                    "does not have enough fields @ line " << linenum << endl;
                cerr << line << endl;
                exit(1);
            }
        }
    } else {
        cerr << "could not open index file " << fname << endl;
        exit(1);
    }
}

// for consistency this should be a class method
bool fastaIndexEntryCompare ( FastaIndexEntry a, FastaIndexEntry b) { return (a.offset<b.offset); }

ostream& operator<<(ostream& output, FastaIndex& fastaIndex) {
    vector<FastaIndexEntry> sortedIndex;
    for(vector<string>::const_iterator it = fastaIndex.sequenceNames.begin(); it != fastaIndex.sequenceNames.end(); ++it)
    {
        sortedIndex.push_back(fastaIndex[*it]);
    }
    sort(sortedIndex.begin(), sortedIndex.end(), fastaIndexEntryCompare);
    for( vector<FastaIndexEntry>::iterator fit = sortedIndex.begin(); fit != sortedIndex.end(); ++fit) {
        output << *fit << endl;
    }
}

void FastaIndex::indexReference(string refname) {
    // overview:
    //  for line in the reference fasta file
    //  track byte offset from the start of the file
    //  if line is a fasta header, take the name and dump the last sequnece to the index
    //  if line is a sequence, add it to the current sequence
    //cerr << "indexing fasta reference " << refname << endl;
    string line;
    FastaIndexEntry entry;  // an entry buffer used in processing
    entry.clear();
    int line_length = 0;
    long long offset = 0;  // byte offset from start of file
    long long line_number = 0; // current line number
    bool mismatchedLineLengths = false; // flag to indicate if our line length changes mid-file
                                        // this will be used to raise an error
                                        // if we have a line length change at
                                        // any line other than the last line in
                                        // the sequence
    bool emptyLine = false;  // flag to catch empty lines, which we allow for
                             // index generation only on the last line of the sequence
    ifstream refFile;
    refFile.open(refname.c_str());
    if (refFile.is_open()) {
        while (getline(refFile, line)) {
            ++line_number;
            line_length = line.length();
            if (line[0] == ';') {
                // fasta comment, skip
            } else if (line[0] == '+') {
                // fastq quality header
                getline(refFile, line);
                line_length = line.length();
                offset += line_length + 1;
                // get and don't handle the quality line
                getline(refFile, line);
                line_length = line.length();
            } else if (line[0] == '>' || line[0] == '@') { // fasta /fastq header
                // if we aren't on the first entry, push the last sequence into the index
                if (entry.name != "") {
                    mismatchedLineLengths = false; // reset line length error tracker for every new sequence
                    emptyLine = false;
                    flushEntryToIndex(entry);
                    entry.clear();
                }
                entry.name = line.substr(1, line_length - 1);
            } else { // we assume we have found a sequence line
                if (entry.offset == -1) // NB initially the offset is -1
                    entry.offset = offset;
                entry.length += line_length;
                if (entry.line_len) {
                    //entry.line_len = entry.line_len ? entry.line_len : line_length + 1;
                    if (mismatchedLineLengths || emptyLine) {
                        if (line_length == 0) {
                            emptyLine = true; // flag empty lines, raise error only if this is embedded in the sequence
                        } else {
                            if (emptyLine) {
                                cerr << "ERROR: embedded newline";
                            } else {
                                cerr << "ERROR: mismatched line lengths";
                            }
                            cerr << " at line " << line_number << " within sequence " << entry.name <<
                                endl << "File not suitable for fasta index generation." << endl;
                            exit(1);
                        }
                    }
                    // this flag is set here and checked on the next line
                    // because we may have reached the end of the sequence, in
                    // which case a mismatched line length is OK
                    if (entry.line_len != line_length + 1) {
                        mismatchedLineLengths = true;
                        if (line_length == 0) {
                            emptyLine = true; // flag empty lines, raise error only if this is embedded in the sequence
                        }
                    }
                } else {
                    entry.line_len = line_length + 1; // first line
                }
                entry.line_blen = entry.line_len - 1;
            }
            offset += line_length + 1;
        }
        // we've hit the end of the fasta file!
        // flush the last entry
        flushEntryToIndex(entry);
    } else {
        cerr << "could not open reference file " << refname << " for indexing!" << endl;
        exit(1);
    }
}

void FastaIndex::flushEntryToIndex(FastaIndexEntry& entry) {
    string name = split(entry.name, " \t").at(0);  // key by first token of name
    sequenceNames.push_back(name);
    this->insert(make_pair(name, FastaIndexEntry(entry.name, entry.length,
                        entry.offset, entry.line_blen,
                        entry.line_len)));

}

void FastaIndex::writeIndexFile(string fname) {
    //cerr << "writing fasta index file " << fname << endl;
    ofstream file;
    file.open(fname.c_str());
    if (file.is_open()) {
        file << *this;
    } else {
        cerr << "could not open index file " << fname << " for writing!" << endl;
        exit(1);
    }
}

FastaIndex::~FastaIndex(void) {
    indexFile.close();
}

FastaIndexEntry FastaIndex::entry(string name) {
    FastaIndex::iterator e = this->find(name);
    if (e == this->end()) {
        cerr << "unable to find FASTA index entry for '" << name << "'" << endl;
        exit(1);
    } else {
        return e->second;
    }
}

string FastaIndex::indexFileExtension() { return ".fai"; }

/*
FastaReference::FastaReference(string reffilename) {
}
*/

void FastaReference::open(string reffilename) {
    filename = reffilename;
    if (!(file = fopen(filename.c_str(), "r"))) {
        cerr << "could not open " << filename << endl;
        exit(1);
    }
    index = new FastaIndex();
    struct stat stFileInfo;
    string indexFileName = filename + index->indexFileExtension();
    // if we can find an index file, use it
    if(stat(indexFileName.c_str(), &stFileInfo) == 0) {
        index->readIndexFile(indexFileName);
    } else { // otherwise, read the reference and generate the index file in the cwd
        cerr << "index file " << indexFileName << " not found, generating..." << endl;
        index->indexReference(filename);
        index->writeIndexFile(indexFileName);
    }
}

FastaReference::~FastaReference(void) {
    fclose(file);
    delete index;
}

string removeIupac(string& str) {
	for (int i=0; i<str.length(); ++i) {
		char c = str[i];
		if (c != 'A' && c != 'T' && c != 'G' && c != 'C' && c != 'N' &&
				c != 'a' && c != 't' && c != 'g' && c != 'c' && c != 'n') {
			str[i] = 'N';
		}
	}
	return str;
}

string FastaReference::getSequence(string seqname) {
    FastaIndexEntry entry = index->entry(seqname);
    int newlines_in_sequence = entry.length / entry.line_blen;
    int seqlen = newlines_in_sequence  + entry.length;
    char* seq = (char*) calloc (seqlen + 1, sizeof(char));
    fseek64(file, entry.offset, SEEK_SET);
    fread(seq, sizeof(char), seqlen, file);
    seq[seqlen] = '\0';
    char* pbegin = seq;
    char* pend = seq + (seqlen/sizeof(char));
    pend = remove(pbegin, pend, '\n');
    pend = remove(pbegin, pend, '\0');
    string s = seq;
    free(seq);
    s.resize((pend - pbegin)/sizeof(char));
	return removeIupac(s);
}

// TODO cleanup; odd function.  use a map
string FastaReference::sequenceNameStartingWith(string seqnameStart) {
    try {
        return (*index)[seqnameStart].name;
    } catch (exception& e) {
        cerr << e.what() << ": unable to find index entry for " << seqnameStart << endl;
        exit(1);
    }
}

string FastaReference::getSubSequence(string seqname, int start, int length) {
    FastaIndexEntry entry = index->entry(seqname);
    length = min(length, entry.length - start);
    if (start < 0 || length < 1) {
        return "";
    }
    // we have to handle newlines
    // approach: count newlines before start
    //           count newlines by end of read
    //             subtracting newlines before start find count of embedded newlines
    int newlines_before = start > 0 ? (start - 1) / entry.line_blen : 0;
    int newlines_by_end = (start + length - 1) / entry.line_blen;
    int newlines_inside = newlines_by_end - newlines_before;
    int seqlen = length + newlines_inside;
    char* seq = (char*) calloc (seqlen + 1, sizeof(char));
    fseek64(file, (off_t) (entry.offset + newlines_before + start), SEEK_SET);
    fread(seq, sizeof(char), (off_t) seqlen, file);
    seq[seqlen] = '\0';
    char* pbegin = seq;
    char* pend = seq + (seqlen/sizeof(char));
    pend = remove(pbegin, pend, '\n');
    pend = remove(pbegin, pend, '\0');
    string s = seq;
    free(seq);
    s.resize((pend - pbegin)/sizeof(char));
	return removeIupac(s);
}

long unsigned int FastaReference::sequenceLength(string seqname) {
    FastaIndexEntry entry = index->entry(seqname);
    return entry.length;
}

<|endoftext|>


<commit_before>//
// Copyright (C) 2014
// Alessio Sclocco <a.sclocco@vu.nl>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
using std::fixed;
#include <iomanip>
using std::setprecision;
#include <ctime>

#include <ArgumentList.hpp>
using isa::utils::ArgumentList;
#include <InitializeOpenCL.hpp>
using isa::OpenCL::initializeOpenCL;
#include <CLData.hpp>
using isa::OpenCL::CLData;
#include <Exceptions.hpp>
using isa::Exceptions::OpenCLError;
#include <Flops.hpp>
using isa::Benchmarks::Flops;
#include <utils.hpp>
using isa::utils::same;

const unsigned int nrIterations = 10;
const unsigned int nrLoops = 100;

int main(int argc, char * argv[]) {
	unsigned int oclPlatform = 0;
	unsigned int oclDevice = 0;
	unsigned int arrayDim = 0;
	unsigned int minThreads = 0;
	unsigned int maxThreads = 0;

	// Parse command line
	if ( argc != 9 ) {
		cerr << "Usage: " << argv[0] << " -opencl_platform <opencl_platform> -opencl_device <opencl_device> -min <min_threads> -max <max_threads>" << endl;
		return 1;
	}

	ArgumentList commandLine(argc, argv);
	try {
		oclPlatform = commandLine.getSwitchArgument< unsigned int >("-opencl_platform");
		oclDevice = commandLine.getSwitchArgument< unsigned int >("-opencl_device");
		minThreads = commandLine.getSwitchArgument< unsigned int >("-min");
		maxThreads = commandLine.getSwitchArgument< unsigned int >("-max");
	} catch ( exception & err ) {
		cerr << err.what() << endl;
		return 1;
	}

	// Initialize OpenCL
	vector< cl::Platform > * oclPlatforms = new vector< cl::Platform >();
	cl::Context * oclContext = new cl::Context();
	vector< cl::Device > * oclDevices = new vector< cl::Device >();
	vector< vector< cl::CommandQueue > > * oclQueues = new vector< vector< cl::CommandQueue > >();
	try {
		initializeOpenCL(oclPlatform, 1, oclPlatforms, oclContext, oclDevices, oclQueues);
	} catch ( OpenCLError err ) {
		cerr << err.what() << endl;
		return 1;
	}
	arrayDim = (oclDevices->at(oclDevice)).getInfo< CL_DEVICE_MAX_MEM_ALLOC_SIZE >();
	arrayDim /= sizeof(float);

	CLData< float > * A = new CLData< float >("A", true);
	CLData< float > * C = new CLData< float >("C", true);

	A->setCLContext(oclContext);
	A->setCLQueue(&(oclQueues->at(oclDevice)[0]));
	A->allocateHostData(arrayDim);
	srand(time(NULL));
	for ( unsigned int i = 0; i < arrayDim; i++ ) {
		A->setHostDataItem(i, 1.0f / static_cast< float >(rand() % 15));
	}
	C->setCLContext(oclContext);
	C->setCLQueue(&(oclQueues->at(oclDevice)[0]));
	C->allocateHostData(arrayDim);
	try {
		A->setDeviceReadOnly();
		A->allocateDeviceData();
		A->copyHostToDevice();
		C->setDeviceWriteOnly();
		C->allocateDeviceData();
	} catch ( OpenCLError err ) {
		cerr << err.what() << endl;
		return 1;
	}

	cout << fixed << setprecision(3) << endl;
	for (unsigned int threads0 = minThreads; threads0 <= maxThreads; threads0 *= 2 ) {
		for (unsigned int threads1 = 1; threads1 <= 32; threads1++ ) {
			if ( (arrayDim % (threads0 * threads1) != 0) || ((threads0 * threads1) > maxThreads) ) {
				continue;
			}

			Flops< float > flops = Flops< float >("float");
			try {
				flops.bindOpenCL(oclContext, &(oclDevices->at(oclDevice)), &(oclQueues->at(oclDevice)[0]));
				flops.setNrThreads(arrayDim);
				flops.setNrThreadsPerBlock(threads0);
				flops.setNrRows(threads1);
				flops.setNrIterations(nrLoops);
				flops.generateCode();

				flops(A, C);
				(flops.getTimer()).reset();
				for ( unsigned int iter = 0; iter < nrIterations; iter++ ) {
					flops(A, C);
				}
			} catch ( OpenCLError err ) {
				cerr << err.what() << endl;
				return 1;
			}

			cout << threads0 << " " << threads1 << " " << flops.getGFLOPs() << " " << flops.getGBs() << endl;

		}
	}
	cout << endl;

	return 0;
}
<commit_msg>The number of kernel loop iterations is defined at runtime.<commit_after>//
// Copyright (C) 2014
// Alessio Sclocco <a.sclocco@vu.nl>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
using std::fixed;
#include <iomanip>
using std::setprecision;
#include <ctime>

#include <ArgumentList.hpp>
using isa::utils::ArgumentList;
#include <InitializeOpenCL.hpp>
using isa::OpenCL::initializeOpenCL;
#include <CLData.hpp>
using isa::OpenCL::CLData;
#include <Exceptions.hpp>
using isa::Exceptions::OpenCLError;
#include <Flops.hpp>
using isa::Benchmarks::Flops;
#include <utils.hpp>
using isa::utils::same;

const unsigned int nrIterations = 10;

int main(int argc, char * argv[]) {
	unsigned int oclPlatform = 0;
	unsigned int oclDevice = 0;
	unsigned int arrayDim = 0;
	unsigned int nrLoops = 0;
	unsigned int minThreads = 0;
	unsigned int maxThreads = 0;

	// Parse command line
	if ( argc != 11 ) {
		cerr << "Usage: " << argv[0] << " -opencl_platform <opencl_platform> -opencl_device <opencl_device> -loops <nr_loops> -min <min_threads> -max <max_threads>" << endl;
		return 1;
	}

	ArgumentList commandLine(argc, argv);
	try {
		oclPlatform = commandLine.getSwitchArgument< unsigned int >("-opencl_platform");
		oclDevice = commandLine.getSwitchArgument< unsigned int >("-opencl_device");
		nrLoops = commandLine.getSwitchArgument< unsigned int >("-loops");
		minThreads = commandLine.getSwitchArgument< unsigned int >("-min");
		maxThreads = commandLine.getSwitchArgument< unsigned int >("-max");
	} catch ( exception & err ) {
		cerr << err.what() << endl;
		return 1;
	}

	// Initialize OpenCL
	vector< cl::Platform > * oclPlatforms = new vector< cl::Platform >();
	cl::Context * oclContext = new cl::Context();
	vector< cl::Device > * oclDevices = new vector< cl::Device >();
	vector< vector< cl::CommandQueue > > * oclQueues = new vector< vector< cl::CommandQueue > >();
	try {
		initializeOpenCL(oclPlatform, 1, oclPlatforms, oclContext, oclDevices, oclQueues);
	} catch ( OpenCLError err ) {
		cerr << err.what() << endl;
		return 1;
	}
	arrayDim = (oclDevices->at(oclDevice)).getInfo< CL_DEVICE_MAX_MEM_ALLOC_SIZE >();
	arrayDim /= sizeof(float);

	CLData< float > * A = new CLData< float >("A", true);
	CLData< float > * C = new CLData< float >("C", true);

	A->setCLContext(oclContext);
	A->setCLQueue(&(oclQueues->at(oclDevice)[0]));
	A->allocateHostData(arrayDim);
	srand(time(NULL));
	for ( unsigned int i = 0; i < arrayDim; i++ ) {
		A->setHostDataItem(i, 1.0f / static_cast< float >(rand() % 15));
	}
	C->setCLContext(oclContext);
	C->setCLQueue(&(oclQueues->at(oclDevice)[0]));
	C->allocateHostData(arrayDim);
	try {
		A->setDeviceReadOnly();
		A->allocateDeviceData();
		A->copyHostToDevice();
		C->setDeviceWriteOnly();
		C->allocateDeviceData();
	} catch ( OpenCLError err ) {
		cerr << err.what() << endl;
		return 1;
	}

	cout << fixed << setprecision(3) << endl;
	for (unsigned int threads0 = minThreads; threads0 <= maxThreads; threads0 *= 2 ) {
		for (unsigned int threads1 = 1; threads1 <= 32; threads1++ ) {
			if ( (arrayDim % (threads0 * threads1) != 0) || ((threads0 * threads1) > maxThreads) ) {
				continue;
			}

			Flops< float > flops = Flops< float >("float");
			try {
				flops.bindOpenCL(oclContext, &(oclDevices->at(oclDevice)), &(oclQueues->at(oclDevice)[0]));
				flops.setNrThreads(arrayDim);
				flops.setNrThreadsPerBlock(threads0);
				flops.setNrRows(threads1);
				flops.setNrIterations(nrLoops);
				flops.generateCode();

				flops(A, C);
				(flops.getTimer()).reset();
				for ( unsigned int iter = 0; iter < nrIterations; iter++ ) {
					flops(A, C);
				}
			} catch ( OpenCLError err ) {
				cerr << err.what() << endl;
				return 1;
			}

			cout << threads0 << " " << threads1 << " " << flops.getGFLOPs() << " " << flops.getGBs() << endl;

		}
	}
	cout << endl;

	return 0;
}
<|endoftext|>


<commit_before>#include "Graph.h"

const int BLACK = 0x00;

Graph::Graph(Screen* s, int sca)
{
    screen = s;
    scale = sca;

    width = s->width;
    height = s->height;

    origin[0] = width/2;
    origin[1] = height/2;

    in = new InputMan();

    running = true;
}

Graph::~Graph(void)
{
}

int units(){[1]
    return {(origin[0]/scale), (origin[1]/scale)};
}

int (*to_graph(int x, int y))[1]
{
    return *{origin[0]+(x*units()[0]), origin[1]-(y*units()[1])};
}

int (*from_graph(int x, int y))[1]
{
    return *{((x-origin[0])/units[0]), -((origin[1]-y)/units[1])};
}

void Graph::update()
{
    input();

    draw_axis();
    for (int i = 0; i < origin[0]; ++i)
    {
        if ((i % scale) == 0)
        {

            // x = 0, y > 0
            screen->set_pixel(origin[0] + 2, origin[1] - i, BLACK);
            screen->set_pixel(origin[0] + 1, origin[1] - i, BLACK);
            screen->set_pixel(origin[0] - 1, origin[1] - i, BLACK);
            screen->set_pixel(origin[0] - 2, origin[1] - i, BLACK);

            // x = 0, y < 0
            screen->set_pixel(origin[0] + 2, i + origin[1], BLACK);
            screen->set_pixel(origin[0] + 1, i + origin[1], BLACK);
            screen->set_pixel(origin[0] - 1, i + origin[1], BLACK);
            screen->set_pixel(origin[0] - 2, i + origin[1], BLACK);

            // y = 0, x > 0
            screen->set_pixel(origin[0] - i, origin[1] + 2, BLACK);
            screen->set_pixel(origin[0] - i, origin[1] + 1, BLACK);
            screen->set_pixel(origin[0] - i, origin[1] - 1, BLACK);
            screen->set_pixel(origin[0] - i, origin[1] - 2, BLACK);

            // y = 0, x < 0
            screen->set_pixel(i + origin[0], origin[1] + 2, BLACK);
            screen->set_pixel(i + origin[0], origin[1] + 1, BLACK);
            screen->set_pixel(i + origin[0], origin[1] - 1, BLACK);
            screen->set_pixel(i + origin[0], origin[1] - 2, BLACK);
        }
    }
}

void Graph::draw_axis()
{
    screen->draw_line(origin[0], 0, origin[0], height, BLACK);
    screen->draw_line(0, origin[1], width, origin[1], BLACK);
}

void Graph::input()
{
    SDL_Event event;
    while(SDL_PollEvent(&event)) {
        switch(event.type) {
        case SDL_QUIT:
            running = false;
            break;
        case SDL_KEYDOWN:
            in->set_key_down(event.key.keysym.sym);
            break;
        case SDL_KEYUP:
           in->set_key_up(event.key.keysym.sym);
           break;
        }
    }

    if (in->get_key(SDLK_ESCAPE))
        running = false;
    if (in->get_key(SDLK_MINUS))
        zoom_out();
    if (in->get_key(SDLK_EQUALS))
        zoom_in();
}

void Graph::zoom_in()
{
    if (scale < origin[0])
        scale += 1;
}

void Graph::zoom_out()
{
    if (scale > 2)
        scale -= 1;
}

<commit_msg>Forgotten Graph:: .<commit_after>#include "Graph.h"

const int BLACK = 0x00;

Graph::Graph(Screen* s, int sca)
{
    screen = s;
    scale = sca;

    width = s->width;
    height = s->height;

    origin[0] = width/2;
    origin[1] = height/2;

    in = new InputMan();

    running = true;
}

Graph::~Graph(void)
{
}

int Graph::units(){[1]
    return {(origin[0]/scale), (origin[1]/scale)};
}

int (*Graph::to_graph(int x, int y))[1]
{
    return *{origin[0]+(x*units()[0]), origin[1]-(y*units()[1])};
}

int (*Graph::from_graph(int x, int y))[1]
{
    return *{((x-origin[0])/units[0]), -((origin[1]-y)/units[1])};
}

void Graph::update()
{
    input();

    draw_axis();
    for (int i = 0; i < origin[0]; ++i)
    {
        if ((i % scale) == 0)
        {

            // x = 0, y > 0
            screen->set_pixel(origin[0] + 2, origin[1] - i, BLACK);
            screen->set_pixel(origin[0] + 1, origin[1] - i, BLACK);
            screen->set_pixel(origin[0] - 1, origin[1] - i, BLACK);
            screen->set_pixel(origin[0] - 2, origin[1] - i, BLACK);

            // x = 0, y < 0
            screen->set_pixel(origin[0] + 2, i + origin[1], BLACK);
            screen->set_pixel(origin[0] + 1, i + origin[1], BLACK);
            screen->set_pixel(origin[0] - 1, i + origin[1], BLACK);
            screen->set_pixel(origin[0] - 2, i + origin[1], BLACK);

            // y = 0, x > 0
            screen->set_pixel(origin[0] - i, origin[1] + 2, BLACK);
            screen->set_pixel(origin[0] - i, origin[1] + 1, BLACK);
            screen->set_pixel(origin[0] - i, origin[1] - 1, BLACK);
            screen->set_pixel(origin[0] - i, origin[1] - 2, BLACK);

            // y = 0, x < 0
            screen->set_pixel(i + origin[0], origin[1] + 2, BLACK);
            screen->set_pixel(i + origin[0], origin[1] + 1, BLACK);
            screen->set_pixel(i + origin[0], origin[1] - 1, BLACK);
            screen->set_pixel(i + origin[0], origin[1] - 2, BLACK);
        }
    }
}

void Graph::draw_axis()
{
    screen->draw_line(origin[0], 0, origin[0], height, BLACK);
    screen->draw_line(0, origin[1], width, origin[1], BLACK);
}

void Graph::input()
{
    SDL_Event event;
    while(SDL_PollEvent(&event)) {
        switch(event.type) {
        case SDL_QUIT:
            running = false;
            break;
        case SDL_KEYDOWN:
            in->set_key_down(event.key.keysym.sym);
            break;
        case SDL_KEYUP:
           in->set_key_up(event.key.keysym.sym);
           break;
        }
    }

    if (in->get_key(SDLK_ESCAPE))
        running = false;
    if (in->get_key(SDLK_MINUS))
        zoom_out();
    if (in->get_key(SDLK_EQUALS))
        zoom_in();
}

void Graph::zoom_in()
{
    if (scale < origin[0])
        scale += 1;
}

void Graph::zoom_out()
{
    if (scale > 2)
        scale -= 1;
}

<|endoftext|>


<commit_before>#include "all.h"

void Graph::addNoodle(Noodle *n, Endpoint from, Endpoint to)
{
	if (m_blocks.find(from.block) == m_blocks.end())
	{
		debug("- block %s(%p) is not in the graph; adding now.\n",
			from.block->name(), from.block);

		bool result = m_blocks.insert(from.block).second;
		assert(result);
	}
	else
	{
		debug("- block %s(%p) is already in the graph.\n",
			from.block->name(), from.block);
	}

	if (m_blocks.find(to.block) == m_blocks.end())
	{
		debug("- block %s(%p) is not in the graph; adding now.\n",
			to.block->name(), to.block);

		bool result = m_blocks.insert(to.block).second;
		assert(result);
	}
	else
	{
		debug("- block %s(%p) is already in the graph.\n",
			to.block->name(), to.block);
	}

	debug("- attempting to connect noodle.\n");

	/* the connect functions will ensure that this is not a duplicate noodle and
	 * that inputs are not connected to multiple noodles */
	from.block->outputs.connect(from.port, n);
	to.block->inputs.connect(to.port, n);

	debug("- adding noodle to the graph.\n");

	bool result = m_noodles.insert(n).second;
	assert(result);

	dumpGraph();

	m_needCheck = true;
}

void Graph::addQNoodle(size_t queue_max, Endpoint from, Endpoint to)
{
	debug("addQNoodle: %s[%s](%p) >>[q:%zu]>> %s[%s](%p)\n",
		from.block->name(), from.port, from.block, queue_max,
		to.block->name(), to.port, to.block);

	QNoodle *n = new QNoodle(queue_max, from, to);
	addNoodle(n, from, to);
}

void Graph::addRNoodle(int init, Endpoint from, Endpoint to)
{
	debug("addRNoodle: %s[%s](%p) >>[r:%d]>> %s[%s](%p)\n",
		from.block->name(), from.port, from.block, init,
		to.block->name(), to.port, to.block);

	RNoodle *n = new RNoodle(init, from, to);
	addNoodle(n, from, to);
}

void Graph::checkGraph(void)
{
	if (!m_needCheck) return;

	debug("checkGraph: checking graph validity\n");

	if (m_noodles.empty())
	{
		throw EmptyGraphException();
	}

	// TODO: check for nodes with no edges (error) [is this possible?]

	m_needCheck = false;
}

void Graph::dumpGraph(void)
{
	static int count = 0;

	/* don't waste time accessing stuff that we won't print */
	if (!verbose) return;

	debug(AT_BLD AT_ULI "\nGRAPH SNAPSHOT #%d\n" AT_RST, ++count);

	for (auto it = m_blocks.cbegin(); it != m_blocks.cend(); ++it)
	{
		Block *b = *it;
		debug("  BLOCK " AT_BLD "%s" AT_RST, str_block(b));

		auto in_begin = b->inputs.m_names.cbegin();
		auto in_end = b->inputs.m_names.cend();
		for (auto in_it = in_begin; in_it != in_end; ++in_it)
		{
			pair<const char *, int> name = *in_it;
			unsigned long num_noodles =
				b->inputs.m_ports.at(b->inputs.m_names.at(name.first)).size();

			debug("\n     in " AT_ULI FG_GRN "%s" AT_RST FG_DEF, name.first);
			if (num_noodles > 0)
			{
				debug(" (" AT_BLD "%lu" AT_RST " noodle%s)",
					num_noodles, (num_noodles == 1 ? "" : "s"));
			}
			else
			{
				debug(" (" FG_RED "unconnected!" FG_DEF ")");
			}
		}

		auto out_begin = b->outputs.m_names.cbegin();
		auto out_end = b->outputs.m_names.cend();
		for (auto out_it = out_begin; out_it != out_end; ++out_it)
		{
			pair<const char *, int> name = *out_it;
			unsigned long num_noodles =
				b->outputs.m_ports.at(b->outputs.m_names.at(name.first)).size();

			debug("\n    out " AT_ULI FG_RED "%s" AT_RST FG_DEF, name.first);
			if (num_noodles > 0)
			{
				debug(" (" AT_BLD "%lu" AT_RST " noodle%s)",
					num_noodles, (num_noodles == 1 ? "" : "s"));
			}
			else
			{
				debug(" (" AT_BLD "unconnected!" AT_RST ")");
			}
		}

		debug("\n\n");
	}

	for (auto it = m_noodles.cbegin(); it != m_noodles.cend(); ++it)
	{
		Noodle *n = *it;

		debug(" NOODLE %s: %s >>> %s", str_noodle(n),
			str_endpoint(&n->m_from, false), str_endpoint(&n->m_to, true));

		if (n->is_qnoodle())
		{
			auto q = dynamic_cast<QNoodle *>(n);
			debug("\n   fill " AT_BLD "%zu" AT_RST "/" AT_BLD "%zu" AT_RST
				"\n  queue {" AT_BLD, q->count(), q->m_max);

			deque<int>& qq = q->m_queue;
			for (auto q_it = qq.cbegin(); q_it != qq.cend(); ++q_it)
			{
				debug(" %d", *q_it);
			}
			debug(AT_RST " }");
		}
		else
		{
			auto r = dynamic_cast<RNoodle *>(n);
			debug("\n    reg " AT_BLD "%d" AT_RST, r->m_reg.load());
		}

		debug("\n\n");
	}

	/* clean up dynamically allocated strings */
	m_strpool.clear();
}

const char *Graph::str_noodle(const Noodle *n)
{
	char *str = m_strpool.alloc(m_strlen);
	if (n->is_qnoodle())
	{
		snprintf(str, m_strlen,
			AT_BLD FG_YLW "QNoodle" AT_RST FG_DEF "@" AT_BLD "%04"
			PRIxPTR AT_RST, ((uintptr_t)n & 0xffff));
	}
	else
	{
		snprintf(str, m_strlen,
			AT_BLD FG_MGT "RNoodle" AT_RST FG_DEF "@" AT_BLD "%04"
			PRIxPTR AT_RST, ((uintptr_t)n & 0xffff));
	}
	return str;
}

const char *Graph::str_block(const Block *b)
{
	char *str = m_strpool.alloc(m_strlen);
	snprintf(str, m_strlen,
		AT_BLD FG_CYN "%s" AT_RST FG_DEF "@" AT_BLD "%04" PRIxPTR AT_RST,
		b->name(), ((uintptr_t)b & 0xffff));
	return str;
}

const char *Graph::str_endpoint(const Endpoint *e, bool input)
{
	char *str = m_strpool.alloc(m_strlen);
	snprintf(str, m_strlen,
		AT_BLD FG_CYN "%s" AT_RST FG_DEF "@" AT_BLD "%04" PRIxPTR AT_RST "["
		AT_ULI "%s%s" AT_RST FG_DEF "]",
		e->block->name(), ((uintptr_t)e->block & 0xffff),
		(input ? FG_GRN : FG_RED), e->port);
	return str;
}
<commit_msg>modify styling of rnoodle register contents<commit_after>#include "all.h"

void Graph::addNoodle(Noodle *n, Endpoint from, Endpoint to)
{
	if (m_blocks.find(from.block) == m_blocks.end())
	{
		debug("- block %s(%p) is not in the graph; adding now.\n",
			from.block->name(), from.block);

		bool result = m_blocks.insert(from.block).second;
		assert(result);
	}
	else
	{
		debug("- block %s(%p) is already in the graph.\n",
			from.block->name(), from.block);
	}

	if (m_blocks.find(to.block) == m_blocks.end())
	{
		debug("- block %s(%p) is not in the graph; adding now.\n",
			to.block->name(), to.block);

		bool result = m_blocks.insert(to.block).second;
		assert(result);
	}
	else
	{
		debug("- block %s(%p) is already in the graph.\n",
			to.block->name(), to.block);
	}

	debug("- attempting to connect noodle.\n");

	/* the connect functions will ensure that this is not a duplicate noodle and
	 * that inputs are not connected to multiple noodles */
	from.block->outputs.connect(from.port, n);
	to.block->inputs.connect(to.port, n);

	debug("- adding noodle to the graph.\n");

	bool result = m_noodles.insert(n).second;
	assert(result);

	dumpGraph();

	m_needCheck = true;
}

void Graph::addQNoodle(size_t queue_max, Endpoint from, Endpoint to)
{
	debug("addQNoodle: %s[%s](%p) >>[q:%zu]>> %s[%s](%p)\n",
		from.block->name(), from.port, from.block, queue_max,
		to.block->name(), to.port, to.block);

	QNoodle *n = new QNoodle(queue_max, from, to);
	addNoodle(n, from, to);
}

void Graph::addRNoodle(int init, Endpoint from, Endpoint to)
{
	debug("addRNoodle: %s[%s](%p) >>[r:%d]>> %s[%s](%p)\n",
		from.block->name(), from.port, from.block, init,
		to.block->name(), to.port, to.block);

	RNoodle *n = new RNoodle(init, from, to);
	addNoodle(n, from, to);
}

void Graph::checkGraph(void)
{
	if (!m_needCheck) return;

	debug("checkGraph: checking graph validity\n");

	if (m_noodles.empty())
	{
		throw EmptyGraphException();
	}

	// TODO: check for nodes with no edges (error) [is this possible?]

	m_needCheck = false;
}

void Graph::dumpGraph(void)
{
	static int count = 0;

	/* don't waste time accessing stuff that we won't print */
	if (!verbose) return;

	debug(AT_BLD AT_ULI "\nGRAPH SNAPSHOT #%d\n" AT_RST, ++count);

	for (auto it = m_blocks.cbegin(); it != m_blocks.cend(); ++it)
	{
		Block *b = *it;
		debug("  BLOCK " AT_BLD "%s" AT_RST, str_block(b));

		auto in_begin = b->inputs.m_names.cbegin();
		auto in_end = b->inputs.m_names.cend();
		for (auto in_it = in_begin; in_it != in_end; ++in_it)
		{
			pair<const char *, int> name = *in_it;
			unsigned long num_noodles =
				b->inputs.m_ports.at(b->inputs.m_names.at(name.first)).size();

			debug("\n     in " AT_ULI FG_GRN "%s" AT_RST FG_DEF, name.first);
			if (num_noodles > 0)
			{
				debug(" (" AT_BLD "%lu" AT_RST " noodle%s)",
					num_noodles, (num_noodles == 1 ? "" : "s"));
			}
			else
			{
				debug(" (" FG_RED "unconnected!" FG_DEF ")");
			}
		}

		auto out_begin = b->outputs.m_names.cbegin();
		auto out_end = b->outputs.m_names.cend();
		for (auto out_it = out_begin; out_it != out_end; ++out_it)
		{
			pair<const char *, int> name = *out_it;
			unsigned long num_noodles =
				b->outputs.m_ports.at(b->outputs.m_names.at(name.first)).size();

			debug("\n    out " AT_ULI FG_RED "%s" AT_RST FG_DEF, name.first);
			if (num_noodles > 0)
			{
				debug(" (" AT_BLD "%lu" AT_RST " noodle%s)",
					num_noodles, (num_noodles == 1 ? "" : "s"));
			}
			else
			{
				debug(" (" AT_BLD "unconnected!" AT_RST ")");
			}
		}

		debug("\n\n");
	}

	for (auto it = m_noodles.cbegin(); it != m_noodles.cend(); ++it)
	{
		Noodle *n = *it;

		debug(" NOODLE %s: %s >>> %s", str_noodle(n),
			str_endpoint(&n->m_from, false), str_endpoint(&n->m_to, true));

		if (n->is_qnoodle())
		{
			auto q = dynamic_cast<QNoodle *>(n);
			debug("\n   fill " AT_BLD "%zu" AT_RST "/" AT_BLD "%zu" AT_RST
				"\n  queue {" AT_BLD, q->count(), q->m_max);

			deque<int>& qq = q->m_queue;
			for (auto q_it = qq.cbegin(); q_it != qq.cend(); ++q_it)
			{
				debug(" %d", *q_it);
			}
			debug(AT_RST " }");
		}
		else
		{
			auto r = dynamic_cast<RNoodle *>(n);
			debug("\n    reg [ " AT_BLD "%d" AT_RST " ]", r->m_reg.load());
		}

		debug("\n\n");
	}

	/* clean up dynamically allocated strings */
	m_strpool.clear();
}

const char *Graph::str_noodle(const Noodle *n)
{
	char *str = m_strpool.alloc(m_strlen);
	if (n->is_qnoodle())
	{
		snprintf(str, m_strlen,
			AT_BLD FG_YLW "QNoodle" AT_RST FG_DEF "@" AT_BLD "%04"
			PRIxPTR AT_RST, ((uintptr_t)n & 0xffff));
	}
	else
	{
		snprintf(str, m_strlen,
			AT_BLD FG_MGT "RNoodle" AT_RST FG_DEF "@" AT_BLD "%04"
			PRIxPTR AT_RST, ((uintptr_t)n & 0xffff));
	}
	return str;
}

const char *Graph::str_block(const Block *b)
{
	char *str = m_strpool.alloc(m_strlen);
	snprintf(str, m_strlen,
		AT_BLD FG_CYN "%s" AT_RST FG_DEF "@" AT_BLD "%04" PRIxPTR AT_RST,
		b->name(), ((uintptr_t)b & 0xffff));
	return str;
}

const char *Graph::str_endpoint(const Endpoint *e, bool input)
{
	char *str = m_strpool.alloc(m_strlen);
	snprintf(str, m_strlen,
		AT_BLD FG_CYN "%s" AT_RST FG_DEF "@" AT_BLD "%04" PRIxPTR AT_RST "["
		AT_ULI "%s%s" AT_RST FG_DEF "]",
		e->block->name(), ((uintptr_t)e->block & 0xffff),
		(input ? FG_GRN : FG_RED), e->port);
	return str;
}
<|endoftext|>