<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2016 Couchbase, Inc.
 *
 *   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 "ep_bucket.h"

#include "bgfetcher.h"
#include "ep_engine.h"
#include "flusher.h"

EPBucket::EPBucket(EventuallyPersistentEngine& theEngine)
    : KVBucket(theEngine) {
}

bool EPBucket::initialize() {
    KVBucket::initialize();

    if (!startBgFetcher()) {
        LOG(EXTENSION_LOG_FATAL,
           "EPBucket::initialize: Failed to create and start bgFetchers");
        return false;
    }
    startFlusher();

    return true;
}

void EPBucket::deinitialize() {
    stopFlusher();
    stopBgFetcher();

    KVBucket::deinitialize();
}

protocol_binary_response_status EPBucket::evictKey(const DocKey& key,
                                                   uint16_t vbucket,
                                                   const char** msg,
                                                   size_t* msg_size) {
    RCPtr<VBucket> vb = getVBucket(vbucket);
    if (!vb || (vb->getState() != vbucket_state_active)) {
        return PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET;
    }

    int bucket_num(0);
    auto lh = vb->ht.getLockedBucket(key, &bucket_num);
    StoredValue* v = vb->fetchValidValue(lh,
                                         key,
                                         bucket_num,
                                         /*wantDeleted*/ false,
                                         /*trackReference*/ false);

    protocol_binary_response_status rv(PROTOCOL_BINARY_RESPONSE_SUCCESS);

    *msg_size = 0;
    if (v) {
        if (v->isResident()) {
            if (vb->ht.unlocked_ejectItem(v, eviction_policy)) {
                *msg = "Ejected.";

                // Add key to bloom filter incase of full eviction mode
                if (getItemEvictionPolicy() == FULL_EVICTION) {
                    vb->addToFilter(key);
                }
            } else {
                *msg = "Can't eject: Dirty object.";
                rv = PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
            }
        } else {
            *msg = "Already ejected.";
        }
    } else {
        if (eviction_policy == VALUE_ONLY) {
            *msg = "Not found.";
            rv = PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
        } else {
            *msg = "Already ejected.";
        }
    }

    return rv;
}

void EPBucket::reset() {
    KVBucket::reset();

    // Need to additionally update disk state
    bool inverse = true;
    flushAllTaskCtx.delayFlushAll.compare_exchange_strong(inverse, false);
    // Waking up (notifying) one flusher is good enough for diskFlushAll
    vbMap.getShard(EP_PRIMARY_SHARD)->getFlusher()->notifyFlushEvent();
}

void EPBucket::startFlusher() {
    for (const auto& shard : vbMap.shards) {
        shard->getFlusher()->start();
    }
}

void EPBucket::stopFlusher() {
    for (uint16_t i = 0; i < vbMap.shards.size(); i++) {
        Flusher* flusher = vbMap.shards[i]->getFlusher();
        LOG(EXTENSION_LOG_NOTICE,
            "Attempting to stop the flusher for "
            "shard:%" PRIu16,
            i);
        bool rv = flusher->stop(stats.forceShutdown);
        if (rv && !stats.forceShutdown) {
            flusher->wait();
        }
    }
}

bool EPBucket::pauseFlusher() {
    bool rv = true;
    for (uint16_t i = 0; i < vbMap.shards.size(); i++) {
        Flusher* flusher = vbMap.shards[i]->getFlusher();
        if (!flusher->pause()) {
            LOG(EXTENSION_LOG_WARNING,
                "Attempted to pause flusher in state "
                "[%s], shard = %d",
                flusher->stateName(),
                i);
            rv = false;
        }
    }
    return rv;
}

bool EPBucket::resumeFlusher() {
    bool rv = true;
    for (uint16_t i = 0; i < vbMap.shards.size(); i++) {
        Flusher* flusher = vbMap.shards[i]->getFlusher();
        if (!flusher->resume()) {
            LOG(EXTENSION_LOG_WARNING,
                "Attempted to resume flusher in state [%s], "
                "shard = %d",
                flusher->stateName(),
                i);
            rv = false;
        }
    }
    return rv;
}

void EPBucket::wakeUpFlusher() {
    if (stats.diskQueueSize.load() == 0) {
        for (uint16_t i = 0; i < vbMap.shards.size(); i++) {
            Flusher *flusher = vbMap.shards[i]->getFlusher();
            flusher->wake();
        }
    }
}

bool EPBucket::startBgFetcher() {
    for (uint16_t i = 0; i < vbMap.shards.size(); i++) {
        BgFetcher* bgfetcher = vbMap.shards[i]->getBgFetcher();
        if (bgfetcher == NULL) {
            LOG(EXTENSION_LOG_WARNING,
                "Failed to start bg fetcher for shard %d",
                i);
            return false;
        }
        bgfetcher->start();
    }
    return true;
}

void EPBucket::stopBgFetcher() {
    for (uint16_t i = 0; i < vbMap.shards.size(); i++) {
        BgFetcher* bgfetcher = vbMap.shards[i]->getBgFetcher();
        if (multiBGFetchEnabled() && bgfetcher->pendingJob()) {
            LOG(EXTENSION_LOG_WARNING,
                "Shutting down engine while there are still pending data "
                "read for shard %d from database storage",
                i);
        }
        LOG(EXTENSION_LOG_NOTICE, "Stopping bg fetcher for shard:%" PRIu16, i);
        bgfetcher->stop();
    }
}

ENGINE_ERROR_CODE EPBucket::getFileStats(const void* cookie,
                                         ADD_STAT add_stat) {
    const auto numShards = vbMap.getNumShards();
    DBFileInfo totalInfo;

    for (uint16_t shardId = 0; shardId < numShards; shardId++) {
        const auto dbInfo =
                getRWUnderlyingByShard(shardId)->getAggrDbFileInfo();
        totalInfo.spaceUsed += dbInfo.spaceUsed;
        totalInfo.fileSize += dbInfo.fileSize;
    }

    add_casted_stat("ep_db_data_size", totalInfo.spaceUsed, add_stat, cookie);
    add_casted_stat("ep_db_file_size", totalInfo.fileSize, add_stat, cookie);

    return ENGINE_SUCCESS;
}

ENGINE_ERROR_CODE EPBucket::getPerVBucketDiskStats(const void* cookie,
                                                   ADD_STAT add_stat) {
    class DiskStatVisitor : public VBucketVisitor {
    public:
        DiskStatVisitor(const void* c, ADD_STAT a) : cookie(c), add_stat(a) {
        }

        void visitBucket(RCPtr<VBucket>& vb) override {
            char buf[32];
            uint16_t vbid = vb->getId();
            DBFileInfo dbInfo =
                    vb->getShard()->getRWUnderlying()->getDbFileInfo(vbid);

            try {
                checked_snprintf(buf, sizeof(buf), "vb_%d:data_size", vbid);
                add_casted_stat(buf, dbInfo.spaceUsed, add_stat, cookie);
                checked_snprintf(buf, sizeof(buf), "vb_%d:file_size", vbid);
                add_casted_stat(buf, dbInfo.fileSize, add_stat, cookie);
            } catch (std::exception& error) {
                LOG(EXTENSION_LOG_WARNING,
                    "DiskStatVisitor::visitBucket: Failed to build stat: %s",
                    error.what());
            }
        }

    private:
        const void* cookie;
        ADD_STAT add_stat;
    };

    DiskStatVisitor dsv(cookie, add_stat);
    visit(dsv);
    return ENGINE_SUCCESS;
}

RCPtr<VBucket> EPBucket::makeVBucket(
        VBucket::id_type id,
        vbucket_state_t state,
        KVShard* shard,
        std::unique_ptr<FailoverTable> table,
        NewSeqnoCallback newSeqnoCb,
        vbucket_state_t initState,
        int64_t lastSeqno,
        uint64_t lastSnapStart,
        uint64_t lastSnapEnd,
        uint64_t purgeSeqno,
        uint64_t maxCas) {
    auto flusherCb = std::make_shared<NotifyFlusherCB>(shard);
    return RCPtr<VBucket>(new VBucket(id,
                                      state,
                                      stats,
                                      engine.getCheckpointConfig(),
                                      shard,
                                      lastSeqno,
                                      lastSnapStart,
                                      lastSnapEnd,
                                      std::move(table),
                                      flusherCb,
                                      std::move(newSeqnoCb),
                                      engine.getConfiguration(),
                                      eviction_policy,
                                      initState,
                                      purgeSeqno,
                                      maxCas));
}
<commit_msg>EPBucket: Use range-for loop for Flusher & BGFetcher iteration<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2016 Couchbase, Inc.
 *
 *   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 "ep_bucket.h"

#include "bgfetcher.h"
#include "ep_engine.h"
#include "flusher.h"

EPBucket::EPBucket(EventuallyPersistentEngine& theEngine)
    : KVBucket(theEngine) {
}

bool EPBucket::initialize() {
    KVBucket::initialize();

    if (!startBgFetcher()) {
        LOG(EXTENSION_LOG_FATAL,
           "EPBucket::initialize: Failed to create and start bgFetchers");
        return false;
    }
    startFlusher();

    return true;
}

void EPBucket::deinitialize() {
    stopFlusher();
    stopBgFetcher();

    KVBucket::deinitialize();
}

protocol_binary_response_status EPBucket::evictKey(const DocKey& key,
                                                   uint16_t vbucket,
                                                   const char** msg,
                                                   size_t* msg_size) {
    RCPtr<VBucket> vb = getVBucket(vbucket);
    if (!vb || (vb->getState() != vbucket_state_active)) {
        return PROTOCOL_BINARY_RESPONSE_NOT_MY_VBUCKET;
    }

    int bucket_num(0);
    auto lh = vb->ht.getLockedBucket(key, &bucket_num);
    StoredValue* v = vb->fetchValidValue(lh,
                                         key,
                                         bucket_num,
                                         /*wantDeleted*/ false,
                                         /*trackReference*/ false);

    protocol_binary_response_status rv(PROTOCOL_BINARY_RESPONSE_SUCCESS);

    *msg_size = 0;
    if (v) {
        if (v->isResident()) {
            if (vb->ht.unlocked_ejectItem(v, eviction_policy)) {
                *msg = "Ejected.";

                // Add key to bloom filter incase of full eviction mode
                if (getItemEvictionPolicy() == FULL_EVICTION) {
                    vb->addToFilter(key);
                }
            } else {
                *msg = "Can't eject: Dirty object.";
                rv = PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS;
            }
        } else {
            *msg = "Already ejected.";
        }
    } else {
        if (eviction_policy == VALUE_ONLY) {
            *msg = "Not found.";
            rv = PROTOCOL_BINARY_RESPONSE_KEY_ENOENT;
        } else {
            *msg = "Already ejected.";
        }
    }

    return rv;
}

void EPBucket::reset() {
    KVBucket::reset();

    // Need to additionally update disk state
    bool inverse = true;
    flushAllTaskCtx.delayFlushAll.compare_exchange_strong(inverse, false);
    // Waking up (notifying) one flusher is good enough for diskFlushAll
    vbMap.getShard(EP_PRIMARY_SHARD)->getFlusher()->notifyFlushEvent();
}

void EPBucket::startFlusher() {
    for (const auto& shard : vbMap.shards) {
        shard->getFlusher()->start();
    }
}

void EPBucket::stopFlusher() {
    for (const auto& shard : vbMap.shards) {
        auto* flusher = shard->getFlusher();
        LOG(EXTENSION_LOG_NOTICE,
            "Attempting to stop the flusher for "
            "shard:%" PRIu16,
            shard->getId());
        bool rv = flusher->stop(stats.forceShutdown);
        if (rv && !stats.forceShutdown) {
            flusher->wait();
        }
    }
}

bool EPBucket::pauseFlusher() {
    bool rv = true;
    for (const auto& shard : vbMap.shards) {
        auto* flusher = shard->getFlusher();
        if (!flusher->pause()) {
            LOG(EXTENSION_LOG_WARNING,
                "Attempted to pause flusher in state "
                "[%s], shard = %d",
                flusher->stateName(),
                shard->getId());
            rv = false;
        }
    }
    return rv;
}

bool EPBucket::resumeFlusher() {
    bool rv = true;
    for (const auto& shard : vbMap.shards) {
        auto* flusher = shard->getFlusher();
        if (!flusher->resume()) {
            LOG(EXTENSION_LOG_WARNING,
                "Attempted to resume flusher in state [%s], "
                "shard = %" PRIu16,
                flusher->stateName(),
                shard->getId());
            rv = false;
        }
    }
    return rv;
}

void EPBucket::wakeUpFlusher() {
    if (stats.diskQueueSize.load() == 0) {
        for (const auto& shard : vbMap.shards) {
            shard->getFlusher()->wake();
        }
    }
}

bool EPBucket::startBgFetcher() {
    for (const auto& shard : vbMap.shards) {
        BgFetcher* bgfetcher = shard->getBgFetcher();
        if (bgfetcher == NULL) {
            LOG(EXTENSION_LOG_WARNING,
                "Failed to start bg fetcher for shard %" PRIu16,
                shard->getId());
            return false;
        }
        bgfetcher->start();
    }
    return true;
}

void EPBucket::stopBgFetcher() {
    for (const auto& shard : vbMap.shards) {
        BgFetcher* bgfetcher = shard->getBgFetcher();
        if (multiBGFetchEnabled() && bgfetcher->pendingJob()) {
            LOG(EXTENSION_LOG_WARNING,
                "Shutting down engine while there are still pending data "
                "read for shard %" PRIu16 " from database storage",
                shard->getId());
        }
        LOG(EXTENSION_LOG_NOTICE,
            "Stopping bg fetcher for shard:%" PRIu16,
            shard->getId());
        bgfetcher->stop();
    }
}

ENGINE_ERROR_CODE EPBucket::getFileStats(const void* cookie,
                                         ADD_STAT add_stat) {
    const auto numShards = vbMap.getNumShards();
    DBFileInfo totalInfo;

    for (uint16_t shardId = 0; shardId < numShards; shardId++) {
        const auto dbInfo =
                getRWUnderlyingByShard(shardId)->getAggrDbFileInfo();
        totalInfo.spaceUsed += dbInfo.spaceUsed;
        totalInfo.fileSize += dbInfo.fileSize;
    }

    add_casted_stat("ep_db_data_size", totalInfo.spaceUsed, add_stat, cookie);
    add_casted_stat("ep_db_file_size", totalInfo.fileSize, add_stat, cookie);

    return ENGINE_SUCCESS;
}

ENGINE_ERROR_CODE EPBucket::getPerVBucketDiskStats(const void* cookie,
                                                   ADD_STAT add_stat) {
    class DiskStatVisitor : public VBucketVisitor {
    public:
        DiskStatVisitor(const void* c, ADD_STAT a) : cookie(c), add_stat(a) {
        }

        void visitBucket(RCPtr<VBucket>& vb) override {
            char buf[32];
            uint16_t vbid = vb->getId();
            DBFileInfo dbInfo =
                    vb->getShard()->getRWUnderlying()->getDbFileInfo(vbid);

            try {
                checked_snprintf(buf, sizeof(buf), "vb_%d:data_size", vbid);
                add_casted_stat(buf, dbInfo.spaceUsed, add_stat, cookie);
                checked_snprintf(buf, sizeof(buf), "vb_%d:file_size", vbid);
                add_casted_stat(buf, dbInfo.fileSize, add_stat, cookie);
            } catch (std::exception& error) {
                LOG(EXTENSION_LOG_WARNING,
                    "DiskStatVisitor::visitBucket: Failed to build stat: %s",
                    error.what());
            }
        }

    private:
        const void* cookie;
        ADD_STAT add_stat;
    };

    DiskStatVisitor dsv(cookie, add_stat);
    visit(dsv);
    return ENGINE_SUCCESS;
}

RCPtr<VBucket> EPBucket::makeVBucket(
        VBucket::id_type id,
        vbucket_state_t state,
        KVShard* shard,
        std::unique_ptr<FailoverTable> table,
        NewSeqnoCallback newSeqnoCb,
        vbucket_state_t initState,
        int64_t lastSeqno,
        uint64_t lastSnapStart,
        uint64_t lastSnapEnd,
        uint64_t purgeSeqno,
        uint64_t maxCas) {
    auto flusherCb = std::make_shared<NotifyFlusherCB>(shard);
    return RCPtr<VBucket>(new VBucket(id,
                                      state,
                                      stats,
                                      engine.getCheckpointConfig(),
                                      shard,
                                      lastSeqno,
                                      lastSnapStart,
                                      lastSnapEnd,
                                      std::move(table),
                                      flusherCb,
                                      std::move(newSeqnoCb),
                                      engine.getConfiguration(),
                                      eviction_policy,
                                      initState,
                                      purgeSeqno,
                                      maxCas));
}
<|endoftext|>


<commit_before>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gpu/command_buffer/service/async_pixel_transfer_manager_idle.h"

#include "base/bind.h"
#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/memory/weak_ptr.h"
#include "gpu/command_buffer/service/safe_shared_memory_pool.h"
#include "ui/gl/scoped_binders.h"

namespace gpu {

namespace {

base::LazyInstance<SafeSharedMemoryPool> g_safe_shared_memory_pool =
    LAZY_INSTANCE_INITIALIZER;

SafeSharedMemoryPool* safe_shared_memory_pool() {
  return g_safe_shared_memory_pool.Pointer();
}

static uint64 g_next_pixel_transfer_state_id = 1;

void PerformNotifyCompletion(
    AsyncMemoryParams mem_params,
    ScopedSafeSharedMemory* safe_shared_memory,
    const AsyncPixelTransferManager::CompletionCallback& callback) {
  TRACE_EVENT0("gpu", "PerformNotifyCompletion");
  AsyncMemoryParams safe_mem_params = mem_params;
  safe_mem_params.shared_memory = safe_shared_memory->shared_memory();
  callback.Run(safe_mem_params);
}

// TODO(backer): Merge this with Delegate in follow-up CL. It serves no purpose.
class AsyncPixelTransferState
    : public base::SupportsWeakPtr<AsyncPixelTransferState> {
 public:
  typedef base::Callback<void(GLuint)> TransferCallback;

  explicit AsyncPixelTransferState(GLuint texture_id)
      : id_(g_next_pixel_transfer_state_id++),
        texture_id_(texture_id),
        transfer_in_progress_(false) {
  }

  virtual ~AsyncPixelTransferState() {}

  bool TransferIsInProgress()  {
    return transfer_in_progress_;
  }

  uint64 id() const { return id_; }

  void set_transfer_in_progress(bool transfer_in_progress) {
    transfer_in_progress_ = transfer_in_progress;
  }

  void PerformTransfer(const TransferCallback& callback) {
    DCHECK(texture_id_);
    DCHECK(transfer_in_progress_);
    callback.Run(texture_id_);
    transfer_in_progress_ = false;
  }

 private:
  uint64 id_;
  GLuint texture_id_;
  bool transfer_in_progress_;

  DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferState);
};

}  // namespace

// Class which handles async pixel transfers in a platform
// independent way.
class AsyncPixelTransferDelegateIdle : public AsyncPixelTransferDelegate,
    public base::SupportsWeakPtr<AsyncPixelTransferDelegateIdle> {
 public:
  AsyncPixelTransferDelegateIdle(
      AsyncPixelTransferManagerIdle::SharedState* state,
      GLuint texture_id);
  virtual ~AsyncPixelTransferDelegateIdle();

  // Implement AsyncPixelTransferDelegate:
  virtual void AsyncTexImage2D(
      const AsyncTexImage2DParams& tex_params,
      const AsyncMemoryParams& mem_params,
      const base::Closure& bind_callback) OVERRIDE;
  virtual void AsyncTexSubImage2D(
      const AsyncTexSubImage2DParams& tex_params,
      const AsyncMemoryParams& mem_params) OVERRIDE;
  virtual bool TransferIsInProgress() OVERRIDE;
  virtual void WaitForTransferCompletion() OVERRIDE;

 private:
  void PerformAsyncTexImage2D(
      AsyncTexImage2DParams tex_params,
      AsyncMemoryParams mem_params,
      const base::Closure& bind_callback,
      ScopedSafeSharedMemory* safe_shared_memory,
      GLuint texture_id);
  void PerformAsyncTexSubImage2D(
      AsyncTexSubImage2DParams tex_params,
      AsyncMemoryParams mem_params,
      ScopedSafeSharedMemory* safe_shared_memory,
      GLuint texture_id);

  // Safe to hold a raw pointer because SharedState is owned by the Manager
  // which owns the Delegate.
  AsyncPixelTransferManagerIdle::SharedState* shared_state_;
  scoped_ptr<AsyncPixelTransferState> state_;

  DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateIdle);
};

AsyncPixelTransferDelegateIdle::AsyncPixelTransferDelegateIdle(
    AsyncPixelTransferManagerIdle::SharedState* shared_state,
    GLuint texture_id)
    : shared_state_(shared_state),
      state_(new AsyncPixelTransferState(texture_id)) {}

AsyncPixelTransferDelegateIdle::~AsyncPixelTransferDelegateIdle() {}

void AsyncPixelTransferDelegateIdle::AsyncTexImage2D(
    const AsyncTexImage2DParams& tex_params,
    const AsyncMemoryParams& mem_params,
    const base::Closure& bind_callback) {
  DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
  DCHECK(mem_params.shared_memory);
  DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
            mem_params.shm_size);

  shared_state_->tasks.push_back(AsyncPixelTransferManagerIdle::Task(
      state_->id(),
      base::Bind(
          &AsyncPixelTransferState::PerformTransfer,
          state_->AsWeakPtr(),
          base::Bind(
              &AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D,
              AsWeakPtr(),
              tex_params,
              mem_params,
              bind_callback,
              base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
                                                     mem_params.shared_memory,
                                                     mem_params.shm_size))))));

  state_->set_transfer_in_progress(true);
}

void AsyncPixelTransferDelegateIdle::AsyncTexSubImage2D(
    const AsyncTexSubImage2DParams& tex_params,
    const AsyncMemoryParams& mem_params) {
  DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
  DCHECK(mem_params.shared_memory);
  DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
            mem_params.shm_size);

  shared_state_->tasks.push_back(AsyncPixelTransferManagerIdle::Task(
      state_->id(),
      base::Bind(
          &AsyncPixelTransferState::PerformTransfer,
          state_->AsWeakPtr(),
          base::Bind(
              &AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D,
              AsWeakPtr(),
              tex_params,
              mem_params,
              base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
                                                     mem_params.shared_memory,
                                                     mem_params.shm_size))))));

  state_->set_transfer_in_progress(true);
}

bool  AsyncPixelTransferDelegateIdle::TransferIsInProgress() {
  return state_->TransferIsInProgress();
}

void AsyncPixelTransferDelegateIdle::WaitForTransferCompletion() {
  for (std::list<AsyncPixelTransferManagerIdle::Task>::iterator iter =
           shared_state_->tasks.begin();
       iter != shared_state_->tasks.end();
       ++iter) {
    if (iter->transfer_id != state_->id())
      continue;

    (*iter).task.Run();
    shared_state_->tasks.erase(iter);
    break;
  }

  shared_state_->ProcessNotificationTasks();
}

void AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D(
    AsyncTexImage2DParams tex_params,
    AsyncMemoryParams mem_params,
    const base::Closure& bind_callback,
    ScopedSafeSharedMemory* safe_shared_memory,
    GLuint texture_id) {
  TRACE_EVENT2("gpu", "PerformAsyncTexImage2D",
               "width", tex_params.width,
               "height", tex_params.height);

  void* data = GetAddress(safe_shared_memory, mem_params);

  gfx::ScopedTextureBinder texture_binder(tex_params.target, texture_id);

  {
    TRACE_EVENT0("gpu", "glTexImage2D");
    glTexImage2D(
        tex_params.target,
        tex_params.level,
        tex_params.internal_format,
        tex_params.width,
        tex_params.height,
        tex_params.border,
        tex_params.format,
        tex_params.type,
        data);
  }

  // The texture is already fully bound so just call it now.
  bind_callback.Run();
}

void AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D(
    AsyncTexSubImage2DParams tex_params,
    AsyncMemoryParams mem_params,
    ScopedSafeSharedMemory* safe_shared_memory,
    GLuint texture_id) {
  TRACE_EVENT2("gpu", "PerformAsyncTexSubImage2D",
               "width", tex_params.width,
               "height", tex_params.height);

  void* data = GetAddress(safe_shared_memory, mem_params);

  base::TimeTicks begin_time(base::TimeTicks::HighResNow());
  gfx::ScopedTextureBinder texture_binder(tex_params.target, texture_id);

  {
    TRACE_EVENT0("gpu", "glTexSubImage2D");
    glTexSubImage2D(
        tex_params.target,
        tex_params.level,
        tex_params.xoffset,
        tex_params.yoffset,
        tex_params.width,
        tex_params.height,
        tex_params.format,
        tex_params.type,
        data);
  }

  shared_state_->texture_upload_count++;
  shared_state_->total_texture_upload_time +=
      base::TimeTicks::HighResNow() - begin_time;
}

AsyncPixelTransferManagerIdle::Task::Task(
    uint64 transfer_id, const base::Closure& task)
    : transfer_id(transfer_id),
      task(task) {
}

AsyncPixelTransferManagerIdle::Task::~Task() {}

AsyncPixelTransferManagerIdle::SharedState::SharedState()
    : texture_upload_count(0) {}

AsyncPixelTransferManagerIdle::SharedState::~SharedState() {}

void AsyncPixelTransferManagerIdle::SharedState::ProcessNotificationTasks() {
  while (!tasks.empty()) {
    // Stop when we reach a pixel transfer task.
    if (tasks.front().transfer_id)
      return;

    tasks.front().task.Run();
    tasks.pop_front();
  }
}

AsyncPixelTransferManagerIdle::AsyncPixelTransferManagerIdle()
  : shared_state_() {
}

AsyncPixelTransferManagerIdle::~AsyncPixelTransferManagerIdle() {}

void AsyncPixelTransferManagerIdle::BindCompletedAsyncTransfers() {
  // Everything is already bound.
}

void AsyncPixelTransferManagerIdle::AsyncNotifyCompletion(
    const AsyncMemoryParams& mem_params,
    const CompletionCallback& callback) {
  if (shared_state_.tasks.empty()) {
    callback.Run(mem_params);
    return;
  }

  shared_state_.tasks.push_back(
      Task(0,  // 0 transfer_id for notification tasks.
           base::Bind(
               &PerformNotifyCompletion,
               mem_params,
               base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
                                                      mem_params.shared_memory,
                                                      mem_params.shm_size)),
               callback)));
}

uint32 AsyncPixelTransferManagerIdle::GetTextureUploadCount() {
  return shared_state_.texture_upload_count;
}

base::TimeDelta AsyncPixelTransferManagerIdle::GetTotalTextureUploadTime() {
  return shared_state_.total_texture_upload_time;
}

void AsyncPixelTransferManagerIdle::ProcessMorePendingTransfers() {
  if (shared_state_.tasks.empty())
    return;

  // First task should always be a pixel transfer task.
  DCHECK(shared_state_.tasks.front().transfer_id);
  shared_state_.tasks.front().task.Run();
  shared_state_.tasks.pop_front();

  shared_state_.ProcessNotificationTasks();
}

bool AsyncPixelTransferManagerIdle::NeedsProcessMorePendingTransfers() {
  return !shared_state_.tasks.empty();
}

AsyncPixelTransferDelegate*
AsyncPixelTransferManagerIdle::CreatePixelTransferDelegateImpl(
    gles2::TextureRef* ref,
    const AsyncTexImage2DParams& define_params) {
  return new AsyncPixelTransferDelegateIdle(&shared_state_, ref->service_id());
}

}  // namespace gpu
<commit_msg>GPU: Eliminate unnecessary State on async idle upload path.<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "gpu/command_buffer/service/async_pixel_transfer_manager_idle.h"

#include "base/bind.h"
#include "base/debug/trace_event.h"
#include "base/lazy_instance.h"
#include "base/memory/weak_ptr.h"
#include "gpu/command_buffer/service/safe_shared_memory_pool.h"
#include "ui/gl/scoped_binders.h"

namespace gpu {

namespace {

base::LazyInstance<SafeSharedMemoryPool> g_safe_shared_memory_pool =
    LAZY_INSTANCE_INITIALIZER;

SafeSharedMemoryPool* safe_shared_memory_pool() {
  return g_safe_shared_memory_pool.Pointer();
}

static uint64 g_next_pixel_transfer_state_id = 1;

void PerformNotifyCompletion(
    AsyncMemoryParams mem_params,
    ScopedSafeSharedMemory* safe_shared_memory,
    const AsyncPixelTransferManager::CompletionCallback& callback) {
  TRACE_EVENT0("gpu", "PerformNotifyCompletion");
  AsyncMemoryParams safe_mem_params = mem_params;
  safe_mem_params.shared_memory = safe_shared_memory->shared_memory();
  callback.Run(safe_mem_params);
}

}  // namespace

// Class which handles async pixel transfers in a platform
// independent way.
class AsyncPixelTransferDelegateIdle
    : public AsyncPixelTransferDelegate,
      public base::SupportsWeakPtr<AsyncPixelTransferDelegateIdle> {
 public:
  AsyncPixelTransferDelegateIdle(
      AsyncPixelTransferManagerIdle::SharedState* state,
      GLuint texture_id);
  virtual ~AsyncPixelTransferDelegateIdle();

  // Implement AsyncPixelTransferDelegate:
  virtual void AsyncTexImage2D(
      const AsyncTexImage2DParams& tex_params,
      const AsyncMemoryParams& mem_params,
      const base::Closure& bind_callback) OVERRIDE;
  virtual void AsyncTexSubImage2D(
      const AsyncTexSubImage2DParams& tex_params,
      const AsyncMemoryParams& mem_params) OVERRIDE;
  virtual bool TransferIsInProgress() OVERRIDE;
  virtual void WaitForTransferCompletion() OVERRIDE;

 private:
  void PerformAsyncTexImage2D(
      AsyncTexImage2DParams tex_params,
      AsyncMemoryParams mem_params,
      const base::Closure& bind_callback,
      ScopedSafeSharedMemory* safe_shared_memory);
  void PerformAsyncTexSubImage2D(
      AsyncTexSubImage2DParams tex_params,
      AsyncMemoryParams mem_params,
      ScopedSafeSharedMemory* safe_shared_memory);

  uint64 id_;
  GLuint texture_id_;
  bool transfer_in_progress_;

  // Safe to hold a raw pointer because SharedState is owned by the Manager
  // which owns the Delegate.
  AsyncPixelTransferManagerIdle::SharedState* shared_state_;

  DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateIdle);
};

AsyncPixelTransferDelegateIdle::AsyncPixelTransferDelegateIdle(
    AsyncPixelTransferManagerIdle::SharedState* shared_state,
    GLuint texture_id)
    : id_(g_next_pixel_transfer_state_id++),
      texture_id_(texture_id),
      transfer_in_progress_(false),
      shared_state_(shared_state) {}

AsyncPixelTransferDelegateIdle::~AsyncPixelTransferDelegateIdle() {}

void AsyncPixelTransferDelegateIdle::AsyncTexImage2D(
    const AsyncTexImage2DParams& tex_params,
    const AsyncMemoryParams& mem_params,
    const base::Closure& bind_callback) {
  DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
  DCHECK(mem_params.shared_memory);
  DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
            mem_params.shm_size);

  shared_state_->tasks.push_back(AsyncPixelTransferManagerIdle::Task(
      id_,
      base::Bind(
          &AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D,
          AsWeakPtr(),
          tex_params,
          mem_params,
          bind_callback,
          base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
                                                 mem_params.shared_memory,
                                                 mem_params.shm_size)))));

  transfer_in_progress_ = true;
}

void AsyncPixelTransferDelegateIdle::AsyncTexSubImage2D(
    const AsyncTexSubImage2DParams& tex_params,
    const AsyncMemoryParams& mem_params) {
  DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
  DCHECK(mem_params.shared_memory);
  DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
            mem_params.shm_size);

  shared_state_->tasks.push_back(AsyncPixelTransferManagerIdle::Task(
      id_,
      base::Bind(
          &AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D,
          AsWeakPtr(),
          tex_params,
          mem_params,
          base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
                                                 mem_params.shared_memory,
                                                 mem_params.shm_size)))));

  transfer_in_progress_ = true;
}

bool  AsyncPixelTransferDelegateIdle::TransferIsInProgress() {
  return transfer_in_progress_;
}

void AsyncPixelTransferDelegateIdle::WaitForTransferCompletion() {
  for (std::list<AsyncPixelTransferManagerIdle::Task>::iterator iter =
           shared_state_->tasks.begin();
       iter != shared_state_->tasks.end();
       ++iter) {
    if (iter->transfer_id != id_)
      continue;

    (*iter).task.Run();
    shared_state_->tasks.erase(iter);
    break;
  }

  shared_state_->ProcessNotificationTasks();
}

void AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D(
    AsyncTexImage2DParams tex_params,
    AsyncMemoryParams mem_params,
    const base::Closure& bind_callback,
    ScopedSafeSharedMemory* safe_shared_memory) {
  TRACE_EVENT2("gpu", "PerformAsyncTexImage2D",
               "width", tex_params.width,
               "height", tex_params.height);

  void* data = GetAddress(safe_shared_memory, mem_params);

  gfx::ScopedTextureBinder texture_binder(tex_params.target, texture_id_);

  {
    TRACE_EVENT0("gpu", "glTexImage2D");
    glTexImage2D(
        tex_params.target,
        tex_params.level,
        tex_params.internal_format,
        tex_params.width,
        tex_params.height,
        tex_params.border,
        tex_params.format,
        tex_params.type,
        data);
  }

  transfer_in_progress_ = false;

  // The texture is already fully bound so just call it now.
  bind_callback.Run();
}

void AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D(
    AsyncTexSubImage2DParams tex_params,
    AsyncMemoryParams mem_params,
    ScopedSafeSharedMemory* safe_shared_memory) {
  TRACE_EVENT2("gpu", "PerformAsyncTexSubImage2D",
               "width", tex_params.width,
               "height", tex_params.height);

  void* data = GetAddress(safe_shared_memory, mem_params);

  base::TimeTicks begin_time(base::TimeTicks::HighResNow());
  gfx::ScopedTextureBinder texture_binder(tex_params.target, texture_id_);

  {
    TRACE_EVENT0("gpu", "glTexSubImage2D");
    glTexSubImage2D(
        tex_params.target,
        tex_params.level,
        tex_params.xoffset,
        tex_params.yoffset,
        tex_params.width,
        tex_params.height,
        tex_params.format,
        tex_params.type,
        data);
  }

  transfer_in_progress_ = false;
  shared_state_->texture_upload_count++;
  shared_state_->total_texture_upload_time +=
      base::TimeTicks::HighResNow() - begin_time;
}

AsyncPixelTransferManagerIdle::Task::Task(
    uint64 transfer_id, const base::Closure& task)
    : transfer_id(transfer_id),
      task(task) {
}

AsyncPixelTransferManagerIdle::Task::~Task() {}

AsyncPixelTransferManagerIdle::SharedState::SharedState()
    : texture_upload_count(0) {}

AsyncPixelTransferManagerIdle::SharedState::~SharedState() {}

void AsyncPixelTransferManagerIdle::SharedState::ProcessNotificationTasks() {
  while (!tasks.empty()) {
    // Stop when we reach a pixel transfer task.
    if (tasks.front().transfer_id)
      return;

    tasks.front().task.Run();
    tasks.pop_front();
  }
}

AsyncPixelTransferManagerIdle::AsyncPixelTransferManagerIdle()
  : shared_state_() {
}

AsyncPixelTransferManagerIdle::~AsyncPixelTransferManagerIdle() {}

void AsyncPixelTransferManagerIdle::BindCompletedAsyncTransfers() {
  // Everything is already bound.
}

void AsyncPixelTransferManagerIdle::AsyncNotifyCompletion(
    const AsyncMemoryParams& mem_params,
    const CompletionCallback& callback) {
  if (shared_state_.tasks.empty()) {
    callback.Run(mem_params);
    return;
  }

  shared_state_.tasks.push_back(
      Task(0,  // 0 transfer_id for notification tasks.
           base::Bind(
               &PerformNotifyCompletion,
               mem_params,
               base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
                                                      mem_params.shared_memory,
                                                      mem_params.shm_size)),
               callback)));
}

uint32 AsyncPixelTransferManagerIdle::GetTextureUploadCount() {
  return shared_state_.texture_upload_count;
}

base::TimeDelta AsyncPixelTransferManagerIdle::GetTotalTextureUploadTime() {
  return shared_state_.total_texture_upload_time;
}

void AsyncPixelTransferManagerIdle::ProcessMorePendingTransfers() {
  if (shared_state_.tasks.empty())
    return;

  // First task should always be a pixel transfer task.
  DCHECK(shared_state_.tasks.front().transfer_id);
  shared_state_.tasks.front().task.Run();
  shared_state_.tasks.pop_front();

  shared_state_.ProcessNotificationTasks();
}

bool AsyncPixelTransferManagerIdle::NeedsProcessMorePendingTransfers() {
  return !shared_state_.tasks.empty();
}

AsyncPixelTransferDelegate*
AsyncPixelTransferManagerIdle::CreatePixelTransferDelegateImpl(
    gles2::TextureRef* ref,
    const AsyncTexImage2DParams& define_params) {
  return new AsyncPixelTransferDelegateIdle(&shared_state_, ref->service_id());
}

}  // namespace gpu
<|endoftext|>


<commit_before>//===-- IPConstantPropagation.cpp - Propagate constants through calls -----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass implements an _extremely_ simple interprocedural constant
// propagation pass.  It could certainly be improved in many different ways,
// like using a worklist.  This pass makes arguments dead, but does not remove
// them.  The existing dead argument elimination pass should be run after this
// to clean up the mess.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "ipconstprop"
#include "llvm/Transforms/IPO.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/SmallVector.h"
using namespace llvm;

STATISTIC(NumArgumentsProped, "Number of args turned into constants");
STATISTIC(NumReturnValProped, "Number of return values turned into constants");

namespace {
  /// IPCP - The interprocedural constant propagation pass
  ///
  struct VISIBILITY_HIDDEN IPCP : public ModulePass {
    static char ID; // Pass identification, replacement for typeid
    IPCP() : ModulePass((intptr_t)&ID) {}

    bool runOnModule(Module &M);
  private:
    bool PropagateConstantsIntoArguments(Function &F);
    bool PropagateConstantReturn(Function &F);
  };
  char IPCP::ID = 0;
  RegisterPass<IPCP> X("ipconstprop", "Interprocedural constant propagation");
}

ModulePass *llvm::createIPConstantPropagationPass() { return new IPCP(); }

bool IPCP::runOnModule(Module &M) {
  bool Changed = false;
  bool LocalChange = true;

  // FIXME: instead of using smart algorithms, we just iterate until we stop
  // making changes.
  while (LocalChange) {
    LocalChange = false;
    for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
      if (!I->isDeclaration()) {
        // Delete any klingons.
        I->removeDeadConstantUsers();
        if (I->hasInternalLinkage())
          LocalChange |= PropagateConstantsIntoArguments(*I);
        Changed |= PropagateConstantReturn(*I);
      }
    Changed |= LocalChange;
  }
  return Changed;
}

/// PropagateConstantsIntoArguments - Look at all uses of the specified
/// function.  If all uses are direct call sites, and all pass a particular
/// constant in for an argument, propagate that constant in as the argument.
///
bool IPCP::PropagateConstantsIntoArguments(Function &F) {
  if (F.arg_empty() || F.use_empty()) return false; // No arguments? Early exit.

  std::vector<std::pair<Constant*, bool> > ArgumentConstants;
  ArgumentConstants.resize(F.arg_size());

  unsigned NumNonconstant = 0;

  for (Value::use_iterator I = F.use_begin(), E = F.use_end(); I != E; ++I)
    if (!isa<Instruction>(*I))
      return false;  // Used by a non-instruction, do not transform
    else {
      CallSite CS = CallSite::get(cast<Instruction>(*I));
      if (CS.getInstruction() == 0 ||
          CS.getCalledFunction() != &F)
        return false;  // Not a direct call site?

      // Check out all of the potentially constant arguments
      CallSite::arg_iterator AI = CS.arg_begin();
      Function::arg_iterator Arg = F.arg_begin();
      for (unsigned i = 0, e = ArgumentConstants.size(); i != e;
           ++i, ++AI, ++Arg) {
        if (*AI == &F) return false;  // Passes the function into itself

        if (!ArgumentConstants[i].second) {
          if (Constant *C = dyn_cast<Constant>(*AI)) {
            if (!ArgumentConstants[i].first)
              ArgumentConstants[i].first = C;
            else if (ArgumentConstants[i].first != C) {
              // Became non-constant
              ArgumentConstants[i].second = true;
              ++NumNonconstant;
              if (NumNonconstant == ArgumentConstants.size()) return false;
            }
          } else if (*AI != &*Arg) {    // Ignore recursive calls with same arg
            // This is not a constant argument.  Mark the argument as
            // non-constant.
            ArgumentConstants[i].second = true;
            ++NumNonconstant;
            if (NumNonconstant == ArgumentConstants.size()) return false;
          }
        }
      }
    }

  // If we got to this point, there is a constant argument!
  assert(NumNonconstant != ArgumentConstants.size());
  Function::arg_iterator AI = F.arg_begin();
  bool MadeChange = false;
  for (unsigned i = 0, e = ArgumentConstants.size(); i != e; ++i, ++AI)
    // Do we have a constant argument!?
    if (!ArgumentConstants[i].second && !AI->use_empty()) {
      Value *V = ArgumentConstants[i].first;
      if (V == 0) V = UndefValue::get(AI->getType());
      AI->replaceAllUsesWith(V);
      ++NumArgumentsProped;
      MadeChange = true;
    }
  return MadeChange;
}

// Check to see if this function returns a constant.  If so, replace all callers
// that user the return value with the returned valued.  If we can replace ALL
// callers,
bool IPCP::PropagateConstantReturn(Function &F) {
  if (F.getReturnType() == Type::VoidTy)
    return false; // No return value.

  // Check to see if this function returns a constant.
  SmallVector<Value *,4> RetVals;
  unsigned N = 0;
  const StructType *STy = dyn_cast<StructType>(F.getReturnType());
  if (STy)
    N = STy->getNumElements();
  else
    N = 1;
  for (unsigned i = 0; i < N; ++i)
    RetVals.push_back(0);

  for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
    if (ReturnInst *RI = dyn_cast<ReturnInst>(BB->getTerminator())) {
      assert (N == RI->getNumOperands() && "Invalid ReturnInst operands!");
      for (unsigned i = 0; i < N; ++i) {
        if (isa<UndefValue>(RI->getOperand(i))) {
          // Ignore
        } else if (Constant *C = dyn_cast<Constant>(RI->getOperand(i))) {
          Value *RV = RetVals[i];
          if (RV == 0)
            RetVals[i] = C;
          else if (RV != C)
            return false; // Does not return the same constant.
        } else {
          return false; // Does not return a constant.
        }
      }
    }

  if (N == 1) {
    if (RetVals[0] == 0)
      RetVals[0] = UndefValue::get(F.getReturnType());
  } else {
    for (unsigned i = 0; i < N; ++i) {
      Value *RetVal = RetVals[i];
      if (RetVal == 0)
        RetVals[i] = UndefValue::get(STy->getElementType(i));
    }
  }

  // If we got here, the function returns a constant value.  Loop over all
  // users, replacing any uses of the return value with the returned constant.
  bool ReplacedAllUsers = true;
  bool MadeChange = false;
  for (Value::use_iterator I = F.use_begin(), E = F.use_end(); I != E; ++I)
    if (!isa<Instruction>(*I))
      ReplacedAllUsers = false;
    else {
      CallSite CS = CallSite::get(cast<Instruction>(*I));
      if (CS.getInstruction() == 0 ||
          CS.getCalledFunction() != &F) {
        ReplacedAllUsers = false;
      } else {
        Instruction *Call = CS.getInstruction();
        if (!Call->use_empty()) {
          if (N == 1)
            Call->replaceAllUsesWith(RetVals[0]);
          else {
            for(Value::use_iterator CUI = Call->use_begin(), CUE = Call->use_end();
                CUI != CUE; ++CUI) {
              GetResultInst *GR = cast<GetResultInst>(CUI);
              GR->replaceAllUsesWith(RetVals[GR->getIndex()]);
              GR->eraseFromParent();
            }
          }
          MadeChange = true;
        }
      }
    }

  // If we replace all users with the returned constant, and there can be no
  // other callers of the function, replace the constant being returned in the
  // function with an undef value.
  if (ReplacedAllUsers && F.hasInternalLinkage()) {
    for (unsigned i = 0; i < N; ++i) {
      Value *RetVal = RetVals[i];
      if (isa<UndefValue>(RetVal))
        continue;
      Value *RV = UndefValue::get(RetVal->getType());
      for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
        if (ReturnInst *RI = dyn_cast<ReturnInst>(BB->getTerminator())) {
          if (RI->getOperand(i) != RV) {
            RI->setOperand(i, RV);
            MadeChange = true;
          }
        }
    }
  }

  if (MadeChange) ++NumReturnValProped;
  return MadeChange;
}
<commit_msg>Incorporate feedback. - Fix loop nest. - Use RetVals.size() - Check for null return value.<commit_after>//===-- IPConstantPropagation.cpp - Propagate constants through calls -----===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass implements an _extremely_ simple interprocedural constant
// propagation pass.  It could certainly be improved in many different ways,
// like using a worklist.  This pass makes arguments dead, but does not remove
// them.  The existing dead argument elimination pass should be run after this
// to clean up the mess.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "ipconstprop"
#include "llvm/Transforms/IPO.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/SmallVector.h"
using namespace llvm;

STATISTIC(NumArgumentsProped, "Number of args turned into constants");
STATISTIC(NumReturnValProped, "Number of return values turned into constants");

namespace {
  /// IPCP - The interprocedural constant propagation pass
  ///
  struct VISIBILITY_HIDDEN IPCP : public ModulePass {
    static char ID; // Pass identification, replacement for typeid
    IPCP() : ModulePass((intptr_t)&ID) {}

    bool runOnModule(Module &M);
  private:
    bool PropagateConstantsIntoArguments(Function &F);
    bool PropagateConstantReturn(Function &F);
  };
  char IPCP::ID = 0;
  RegisterPass<IPCP> X("ipconstprop", "Interprocedural constant propagation");
}

ModulePass *llvm::createIPConstantPropagationPass() { return new IPCP(); }

bool IPCP::runOnModule(Module &M) {
  bool Changed = false;
  bool LocalChange = true;

  // FIXME: instead of using smart algorithms, we just iterate until we stop
  // making changes.
  while (LocalChange) {
    LocalChange = false;
    for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
      if (!I->isDeclaration()) {
        // Delete any klingons.
        I->removeDeadConstantUsers();
        if (I->hasInternalLinkage())
          LocalChange |= PropagateConstantsIntoArguments(*I);
        Changed |= PropagateConstantReturn(*I);
      }
    Changed |= LocalChange;
  }
  return Changed;
}

/// PropagateConstantsIntoArguments - Look at all uses of the specified
/// function.  If all uses are direct call sites, and all pass a particular
/// constant in for an argument, propagate that constant in as the argument.
///
bool IPCP::PropagateConstantsIntoArguments(Function &F) {
  if (F.arg_empty() || F.use_empty()) return false; // No arguments? Early exit.

  std::vector<std::pair<Constant*, bool> > ArgumentConstants;
  ArgumentConstants.resize(F.arg_size());

  unsigned NumNonconstant = 0;

  for (Value::use_iterator I = F.use_begin(), E = F.use_end(); I != E; ++I)
    if (!isa<Instruction>(*I))
      return false;  // Used by a non-instruction, do not transform
    else {
      CallSite CS = CallSite::get(cast<Instruction>(*I));
      if (CS.getInstruction() == 0 ||
          CS.getCalledFunction() != &F)
        return false;  // Not a direct call site?

      // Check out all of the potentially constant arguments
      CallSite::arg_iterator AI = CS.arg_begin();
      Function::arg_iterator Arg = F.arg_begin();
      for (unsigned i = 0, e = ArgumentConstants.size(); i != e;
           ++i, ++AI, ++Arg) {
        if (*AI == &F) return false;  // Passes the function into itself

        if (!ArgumentConstants[i].second) {
          if (Constant *C = dyn_cast<Constant>(*AI)) {
            if (!ArgumentConstants[i].first)
              ArgumentConstants[i].first = C;
            else if (ArgumentConstants[i].first != C) {
              // Became non-constant
              ArgumentConstants[i].second = true;
              ++NumNonconstant;
              if (NumNonconstant == ArgumentConstants.size()) return false;
            }
          } else if (*AI != &*Arg) {    // Ignore recursive calls with same arg
            // This is not a constant argument.  Mark the argument as
            // non-constant.
            ArgumentConstants[i].second = true;
            ++NumNonconstant;
            if (NumNonconstant == ArgumentConstants.size()) return false;
          }
        }
      }
    }

  // If we got to this point, there is a constant argument!
  assert(NumNonconstant != ArgumentConstants.size());
  Function::arg_iterator AI = F.arg_begin();
  bool MadeChange = false;
  for (unsigned i = 0, e = ArgumentConstants.size(); i != e; ++i, ++AI)
    // Do we have a constant argument!?
    if (!ArgumentConstants[i].second && !AI->use_empty()) {
      Value *V = ArgumentConstants[i].first;
      if (V == 0) V = UndefValue::get(AI->getType());
      AI->replaceAllUsesWith(V);
      ++NumArgumentsProped;
      MadeChange = true;
    }
  return MadeChange;
}

// Check to see if this function returns a constant.  If so, replace all callers
// that user the return value with the returned valued.  If we can replace ALL
// callers,
bool IPCP::PropagateConstantReturn(Function &F) {
  if (F.getReturnType() == Type::VoidTy)
    return false; // No return value.

  // Check to see if this function returns a constant.
  SmallVector<Value *,4> RetVals;
  const StructType *STy = dyn_cast<StructType>(F.getReturnType());
  if (STy)
    RetVals.assign(STy->getNumElements(), 0);
  else
    RetVals.push_back(0);

  for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
    if (ReturnInst *RI = dyn_cast<ReturnInst>(BB->getTerminator())) {
      unsigned RetValsSize = RetVals.size();
      assert (RetValsSize == RI->getNumOperands() && "Invalid ReturnInst operands!");
      for (unsigned i = 0; i < RetValsSize; ++i) {
        if (isa<UndefValue>(RI->getOperand(i))) {
          // Ignore
        } else if (Constant *C = dyn_cast<Constant>(RI->getOperand(i))) {
          Value *RV = RetVals[i];
          if (RV == 0)
            RetVals[i] = C;
          else if (RV != C)
            return false; // Does not return the same constant.
        } else {
          return false; // Does not return a constant.
        }
      }
    }

  if (STy) {
    for (unsigned i = 0, e = RetVals.size(); i < e; ++i)
      if (RetVals[i] == 0)
        RetVals[i] = UndefValue::get(STy->getElementType(i));
  } else {
    if (RetVals.size() == 1)
      if (RetVals[0] == 0)
        RetVals[0] = UndefValue::get(F.getReturnType());
  }

  // If we got here, the function returns a constant value.  Loop over all
  // users, replacing any uses of the return value with the returned constant.
  bool ReplacedAllUsers = true;
  bool MadeChange = false;
  for (Value::use_iterator I = F.use_begin(), E = F.use_end(); I != E; ++I)
    if (!isa<Instruction>(*I))
      ReplacedAllUsers = false;
    else {
      CallSite CS = CallSite::get(cast<Instruction>(*I));
      if (CS.getInstruction() == 0 ||
          CS.getCalledFunction() != &F) {
        ReplacedAllUsers = false;
      } else {
        Instruction *Call = CS.getInstruction();
        if (!Call->use_empty()) {
          if (RetVals.size() == 1)
            Call->replaceAllUsesWith(RetVals[0]);
          else {
            for(Value::use_iterator CUI = Call->use_begin(), CUE = Call->use_end();
                CUI != CUE; ++CUI) {
              GetResultInst *GR = cast<GetResultInst>(CUI);
              if (RetVals[GR->getIndex()]) {
                GR->replaceAllUsesWith(RetVals[GR->getIndex()]);
                GR->eraseFromParent();
              }
            }
          }
          MadeChange = true;
        }
      }
    }

  // If we replace all users with the returned constant, and there can be no
  // other callers of the function, replace the constant being returned in the
  // function with an undef value.
  if (ReplacedAllUsers && F.hasInternalLinkage()) {
    for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) {
      if (ReturnInst *RI = dyn_cast<ReturnInst>(BB->getTerminator())) {
        for (unsigned i = 0, e = RetVals.size(); i < e; ++i) {
          Value *RetVal = RetVals[i];
          if (isa<UndefValue>(RetVal))
            continue;
          Value *RV = UndefValue::get(RetVal->getType());
          if (RI->getOperand(i) != RV) {
            RI->setOperand(i, RV);
            MadeChange = true;
          }
        }
      }
    }
  }

  if (MadeChange) ++NumReturnValProped;
  return MadeChange;
}
<|endoftext|>


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

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkSimpleFilterWatcher.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details.

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

=========================================================================*/

#include "itkSimpleFilterWatcher.h"

namespace itk
{

SimpleFilterWatcher
::SimpleFilterWatcher(ProcessObject* o, char *comment)
{
  // Initialize state
  m_Start = 0;
  m_End = 0;
  m_Process = o;
  m_Steps = 0;
  m_Comment = comment;
  m_TestAbort = false;
#if defined(_COMPILER_VERSION) && (_COMPILER_VERSION == 730)
  m_Quiet = true;
#else
  m_Quiet = false;
#endif

  // Create a series of commands
  m_StartFilterCommand =      CommandType::New();
  m_EndFilterCommand =        CommandType::New();
  m_ProgressFilterCommand =   CommandType::New();
  m_IterationFilterCommand =  CommandType::New();
  m_AbortFilterCommand =      CommandType::New();

  // Assign the callbacks
  m_StartFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::StartFilter);
  m_EndFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::EndFilter);
  m_ProgressFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowProgress);
  m_IterationFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowIteration);
  m_AbortFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowAbort);

  // Add the commands as observers
  m_StartTag = m_Process->AddObserver(StartEvent(), m_StartFilterCommand);
  m_EndTag = m_Process->AddObserver(EndEvent(), m_EndFilterCommand);
  m_ProgressTag
    = m_Process->AddObserver(ProgressEvent(), m_ProgressFilterCommand);
  m_IterationTag
    = m_Process->AddObserver(IterationEvent(), m_IterationFilterCommand);
  m_AbortTag
    = m_Process->AddObserver(AbortEvent(), m_AbortFilterCommand);
}

SimpleFilterWatcher
::SimpleFilterWatcher()
{
  // Initialize state
  m_Start = 0;
  m_End = 0;
  m_Steps = 0;
  m_Comment = "Not watching an object";
  m_TestAbort = false;
#if defined(_COMPILER_VERSION) && (_COMPILER_VERSION == 730)
  m_Quiet = true;
#else
  m_Quiet = false;
#endif

  m_Process = 0;
}

SimpleFilterWatcher
::SimpleFilterWatcher(const SimpleFilterWatcher &watch)
{
  // Remove any observers we have on the old process object
  if (m_Process)
    {
    if (m_StartFilterCommand)
      {
      m_Process->RemoveObserver(m_StartTag);
      }
    if (m_EndFilterCommand)
      {
      m_Process->RemoveObserver(m_EndTag);
      }
    if (m_ProgressFilterCommand)
      {
      m_Process->RemoveObserver(m_ProgressTag);
      }
    if (m_IterationFilterCommand)
      {
      m_Process->RemoveObserver(m_IterationTag);
      }
    if (m_AbortFilterCommand)
      {
      m_Process->RemoveObserver(m_AbortTag);
      }
    }

  // Initialize state
  m_Start = watch.m_Start;
  m_End = watch.m_End;
  m_Process = watch.m_Process;
  m_Steps = watch.m_Steps;
  m_Comment = watch.m_Comment;
  m_TestAbort = watch.m_TestAbort;
  m_Quiet = watch.m_Quiet;

  m_StartTag = 0;
  m_EndTag = 0;
  m_ProgressTag = 0;
  m_IterationTag = 0;
  m_AbortTag = 0;

  // Create a series of commands
  if (m_Process)
    {
    m_StartFilterCommand =      CommandType::New();
    m_EndFilterCommand =        CommandType::New();
    m_ProgressFilterCommand =   CommandType::New();
    m_IterationFilterCommand =  CommandType::New();
    m_AbortFilterCommand =      CommandType::New();

    // Assign the callbacks
    m_StartFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::StartFilter);
    m_EndFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::EndFilter);
    m_ProgressFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowProgress);
    m_IterationFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowIteration);
    m_AbortFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowAbort);

    // Add the commands as observers
    m_StartTag = m_Process->AddObserver(StartEvent(), m_StartFilterCommand);
    m_EndTag = m_Process->AddObserver(EndEvent(), m_EndFilterCommand);
    m_ProgressTag
      = m_Process->AddObserver(ProgressEvent(), m_ProgressFilterCommand);
    m_IterationTag
      = m_Process->AddObserver(IterationEvent(), m_IterationFilterCommand);
    m_AbortTag = m_Process->AddObserver(AbortEvent(), m_AbortFilterCommand);
    }
}

void
SimpleFilterWatcher
::operator=(const SimpleFilterWatcher &watch)
{
  // Remove any observers we have on the old process object
  if (m_Process)
    {
    if (m_StartFilterCommand)
      {
      m_Process->RemoveObserver(m_StartTag);
      }
    if (m_EndFilterCommand)
      {
      m_Process->RemoveObserver(m_EndTag);
      }
    if (m_ProgressFilterCommand)
      {
      m_Process->RemoveObserver(m_ProgressTag);
      }
    if (m_IterationFilterCommand)
      {
      m_Process->RemoveObserver(m_IterationTag);
      }
    if (m_AbortFilterCommand)
      {
      m_Process->RemoveObserver(m_AbortTag);
      }
    }

  // Initialize state
  m_Start = watch.m_Start;
  m_End = watch.m_End;
  m_Process = watch.m_Process;
  m_Steps = watch.m_Steps;
  m_Comment = watch.m_Comment;
  m_TestAbort = watch.m_TestAbort;
  m_Quiet = watch.m_Quiet;

  m_StartTag = 0;
  m_EndTag = 0;
  m_ProgressTag = 0;
  m_IterationTag = 0;
  m_AbortTag = 0;

  // Create a series of commands
  if (m_Process)
    {
    m_StartFilterCommand =      CommandType::New();
    m_EndFilterCommand =        CommandType::New();
    m_ProgressFilterCommand =   CommandType::New();
    m_IterationFilterCommand =  CommandType::New();
    m_AbortFilterCommand =      CommandType::New();

    // Assign the callbacks
    m_StartFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::StartFilter);
    m_EndFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::EndFilter);
    m_ProgressFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowProgress);
    m_IterationFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowIteration);
    m_AbortFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowAbort);

    // Add the commands as observers
    m_StartTag = m_Process->AddObserver(StartEvent(), m_StartFilterCommand);
    m_EndTag = m_Process->AddObserver(EndEvent(), m_EndFilterCommand);
    m_ProgressTag
      = m_Process->AddObserver(ProgressEvent(), m_ProgressFilterCommand);
    m_IterationTag
      = m_Process->AddObserver(IterationEvent(), m_IterationFilterCommand);
    m_AbortTag = m_Process->AddObserver(AbortEvent(), m_AbortFilterCommand);
    }
}

SimpleFilterWatcher
::~SimpleFilterWatcher()
{
  // Remove any observers we have on the old process object
  if (m_Process)
    {
    if (m_StartFilterCommand)
      {
      m_Process->RemoveObserver(m_StartTag);
      }
    if (m_EndFilterCommand)
      {
      m_Process->RemoveObserver(m_EndTag);
      }
    if (m_ProgressFilterCommand)
      {
      m_Process->RemoveObserver(m_ProgressTag);
      }
    if (m_IterationFilterCommand)
      {
      m_Process->RemoveObserver(m_IterationTag);
      }
    if (m_AbortFilterCommand)
      {
      m_Process->RemoveObserver(m_AbortTag);
      }
    }
}

} // end namespace itk

<commit_msg>BUG: Added copy constructor and operator= so filter watcher properly manages commands and observers<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkSimpleFilterWatcher.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

  Portions of this code are covered under the VTK copyright.
  See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details.

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

=========================================================================*/

#include "itkSimpleFilterWatcher.h"

namespace itk
{

SimpleFilterWatcher
::SimpleFilterWatcher(ProcessObject* o, char *comment)
{
  // Initialize state
  m_Start = 0;
  m_End = 0;
  m_Process = o;
  m_Steps = 0;
  m_Comment = comment;
  m_TestAbort = false;
#if defined(_COMPILER_VERSION) && (_COMPILER_VERSION == 730)
  m_Quiet = true;
#else
  m_Quiet = false;
#endif

  // Create a series of commands
  m_StartFilterCommand =      CommandType::New();
  m_EndFilterCommand =        CommandType::New();
  m_ProgressFilterCommand =   CommandType::New();
  m_IterationFilterCommand =  CommandType::New();
  m_AbortFilterCommand =      CommandType::New();

  // Assign the callbacks
  m_StartFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::StartFilter);
  m_EndFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::EndFilter);
  m_ProgressFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowProgress);
  m_IterationFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowIteration);
  m_AbortFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowAbort);

  // Add the commands as observers
  m_StartTag = m_Process->AddObserver(StartEvent(), m_StartFilterCommand);
  m_EndTag = m_Process->AddObserver(EndEvent(), m_EndFilterCommand);
  m_ProgressTag
    = m_Process->AddObserver(ProgressEvent(), m_ProgressFilterCommand);
  m_IterationTag
    = m_Process->AddObserver(IterationEvent(), m_IterationFilterCommand);
  m_AbortTag
    = m_Process->AddObserver(AbortEvent(), m_AbortFilterCommand);
}

SimpleFilterWatcher
::SimpleFilterWatcher()
{
  // Initialize state
  m_Start = 0;
  m_End = 0;
  m_Steps = 0;
  m_Comment = "Not watching an object";
  m_TestAbort = false;
#if defined(_COMPILER_VERSION) && (_COMPILER_VERSION == 730)
  m_Quiet = true;
#else
  m_Quiet = false;
#endif

  m_Process = 0;
}

SimpleFilterWatcher
::SimpleFilterWatcher(const SimpleFilterWatcher &watch)
{
  // Remove any observers we have on the old process object
  if (m_Process)
    {
    if (m_StartFilterCommand)
      {
      m_Process->RemoveObserver(m_StartTag);
      }
    if (m_EndFilterCommand)
      {
      m_Process->RemoveObserver(m_EndTag);
      }
    if (m_ProgressFilterCommand)
      {
      m_Process->RemoveObserver(m_ProgressTag);
      }
    if (m_IterationFilterCommand)
      {
      m_Process->RemoveObserver(m_IterationTag);
      }
    if (m_AbortFilterCommand)
      {
      m_Process->RemoveObserver(m_AbortTag);
      }
    }

  // Initialize state
  m_Start = watch.m_Start;
  m_End = watch.m_End;
  m_Process = watch.m_Process;
  m_Steps = watch.m_Steps;
  m_Comment = watch.m_Comment;
  m_TestAbort = watch.m_TestAbort;
  m_Quiet = watch.m_Quiet;

  m_StartTag = 0;
  m_EndTag = 0;
  m_ProgressTag = 0;
  m_IterationTag = 0;
  m_AbortTag = 0;

  // Create a series of commands
  if (m_Process)
    {
    m_StartFilterCommand =      CommandType::New();
    m_EndFilterCommand =        CommandType::New();
    m_ProgressFilterCommand =   CommandType::New();
    m_IterationFilterCommand =  CommandType::New();
    m_AbortFilterCommand =      CommandType::New();

    // Assign the callbacks
    m_StartFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::StartFilter);
    m_EndFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::EndFilter);
    m_ProgressFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowProgress);
    m_IterationFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowIteration);
    m_AbortFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowAbort);

    // Add the commands as observers
    m_StartTag = m_Process->AddObserver(StartEvent(), m_StartFilterCommand);
    m_EndTag = m_Process->AddObserver(EndEvent(), m_EndFilterCommand);
    m_ProgressTag
      = m_Process->AddObserver(ProgressEvent(), m_ProgressFilterCommand);
    m_IterationTag
      = m_Process->AddObserver(IterationEvent(), m_IterationFilterCommand);
    m_AbortTag = m_Process->AddObserver(AbortEvent(), m_AbortFilterCommand);
    }
}

void
SimpleFilterWatcher
::operator=(const SimpleFilterWatcher &watch)
{
  // Remove any observers we have on the old process object
  if (m_Process)
    {
    if (m_StartFilterCommand)
      {
      m_Process->RemoveObserver(m_StartTag);
      }
    if (m_EndFilterCommand)
      {
      m_Process->RemoveObserver(m_EndTag);
      }
    if (m_ProgressFilterCommand)
      {
      m_Process->RemoveObserver(m_ProgressTag);
      }
    if (m_IterationFilterCommand)
      {
      m_Process->RemoveObserver(m_IterationTag);
      }
    if (m_AbortFilterCommand)
      {
      m_Process->RemoveObserver(m_AbortTag);
      }
    }

  // Initialize state
  m_Start = watch.m_Start;
  m_End = watch.m_End;
  m_Process = watch.m_Process;
  m_Steps = watch.m_Steps;
  m_Comment = watch.m_Comment;
  m_TestAbort = watch.m_TestAbort;
  m_Quiet = watch.m_Quiet;

  m_StartTag = 0;
  m_EndTag = 0;
  m_ProgressTag = 0;
  m_IterationTag = 0;
  m_AbortTag = 0;

  // Create a series of commands
  if (m_Process)
    {
    m_StartFilterCommand =      CommandType::New();
    m_EndFilterCommand =        CommandType::New();
    m_ProgressFilterCommand =   CommandType::New();
    m_IterationFilterCommand =  CommandType::New();
    m_AbortFilterCommand =      CommandType::New();

    // Assign the callbacks
    m_StartFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::StartFilter);
    m_EndFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::EndFilter);
    m_ProgressFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowProgress);
    m_IterationFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowIteration);
    m_AbortFilterCommand->SetCallbackFunction(this,
                                        &SimpleFilterWatcher::ShowAbort);

    // Add the commands as observers
    m_StartTag = m_Process->AddObserver(StartEvent(), m_StartFilterCommand);
    m_EndTag = m_Process->AddObserver(EndEvent(), m_EndFilterCommand);
    m_ProgressTag
      = m_Process->AddObserver(ProgressEvent(), m_ProgressFilterCommand);
    m_IterationTag
      = m_Process->AddObserver(IterationEvent(), m_IterationFilterCommand);
    m_AbortTag = m_Process->AddObserver(AbortEvent(), m_AbortFilterCommand);
    }
}

SimpleFilterWatcher
::~SimpleFilterWatcher()
{
  // Remove any observers we have on the old process object
  if (m_Process)
    {
    if (m_StartFilterCommand)
      {
      m_Process->RemoveObserver(m_StartTag);
      }
    if (m_EndFilterCommand)
      {
      m_Process->RemoveObserver(m_EndTag);
      }
    if (m_ProgressFilterCommand)
      {
      m_Process->RemoveObserver(m_ProgressTag);
      }
    if (m_IterationFilterCommand)
      {
      m_Process->RemoveObserver(m_IterationTag);
      }
    if (m_AbortFilterCommand)
      {
      m_Process->RemoveObserver(m_AbortTag);
      }
    }
}

} // end namespace itk

<|endoftext|>


<commit_before>/**
 * This file implements a command line utility to interact
 * with the `d2` library.
 */

#include <boost/exception/diagnostic_information.hpp>
#include <boost/exception/get_error_info.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/make_shared.hpp>
#include <boost/program_options.hpp>
#include <boost/shared_ptr.hpp>
#include <cstdlib> // EXIT_FAILURE, EXIT_SUCCESS
#include <d2/core/diagnostic.hpp>
#include <d2/core/exceptions.hpp>
#include <d2/core/filesystem.hpp>
#include <d2/core/synchronization_skeleton.hpp>
#include <exception>
#include <iostream>
#include <string>

namespace {
namespace po = boost::program_options;

class Driver {
    /**
     * Return a string representation of the data associated to an `ErrorTag`.
     *
     * If no data associated to that tag is present in the exception object,
     * `default_` is returned instead.
     */
    template <typename ErrorTag, typename Exception>
    static std::string
    get_error_info(Exception const& e, std::string default_ = "unavailable") {
        typedef typename ErrorTag::value_type Info;
        Info const* info = boost::get_error_info<ErrorTag>(e);
        return info ? boost::lexical_cast<std::string>(*info) : default_;
    }

    typedef d2::core::synchronization_skeleton Skeleton;

    //! Print an error to the standard error stream with a trailing newline.
    template <typename Printable>
    static void error(Printable const& p) {
        std::cerr << "d2: error: " << p << '\n';
    }

    /**
     * Return a pointer to a `synchronization_skeleton` loaded with the data
     * found in the repository, or a default initialized `shared_ptr` if
     * anything goes wrong.
     */
    boost::shared_ptr<Skeleton> create_skeleton() const {
        if (!boost::filesystem::exists(repo)) {
            error(repo + " does not exist");
            return boost::shared_ptr<Skeleton>();
        }

        try {
            return boost::make_shared<Skeleton>(repo);

        } catch (d2::core::filesystem_error const& e) {
            error("unable to open the repository at " + repo);
            if (debug)
                error(boost::diagnostic_information(e));

        } catch (d2::EventTypeException const& e) {
            std::string actual_type = get_error_info<d2::ActualType>(e);
            std::string expected_type = get_error_info<d2::ExpectedType>(e);

            error(boost::format(
                    "while building the graphs:\n"
                    "    encountered an event of type %1%\n"
                    "    while expecting an event of type %2%")
                    % actual_type % expected_type);
            if (debug)
                error(boost::diagnostic_information(e));

        } catch (d2::UnexpectedReleaseException const& e) {
            std::string lock = get_error_info<d2::ReleasedLock>(e);
            std::string thread = get_error_info<d2::ReleasingThread>(e);

            error(boost::format(
                    "while building the graphs:\n"
                    "    lock %1% was unexpectedly released by thread %2%")
                    % lock % thread);

             if (debug)
                error(boost::diagnostic_information(e));
        }
        return boost::shared_ptr<Skeleton>();
    }

    bool parse_command_line(int argc, char const* argv[]) {
        po::variables_map args;
        po::options_description visible, hidden, all;
        po::positional_options_description positionals;
        bool help = false;

        visible.add_options()
        (
            "help,h",
            po::bool_switch(&help),
            "produce help message and exit"
        )(
            "analyze",
            po::bool_switch(&analyze)->default_value(true, "true"),
            "perform the analysis for deadlocks"
        )(
            "stats",
            po::bool_switch(&stats),
            "produce statistics about the usage of locks and threads"
        )(
            "debug",
            po::bool_switch(&debug),
            "enable special debugging output"
        )
        ;

        hidden.add_options()
        (
            "repo-path",
            po::value<std::string>(&repo),
            "path of the repository to examine"
        )
        ;

        positionals.add("repo-path", 1);
        all.add(visible).add(hidden);

        po::command_line_parser parser(argc, argv);
        try {
            po::store(parser.options(all).positional(positionals).run(), args);
        } catch (po::error const& e) {
            error(e.what());
            return false;
        }
        po::notify(args);

        if (help) {
            std::cout << visible;
            return false;
        }

        if (repo.empty()) {
            error("missing input directory");
            return false;
        }

        return true;
    }

    std::string repo;
    bool debug, analyze, stats;

    static void print_deadlock(d2::core::potential_deadlock const& dl) {
        std::cout <<
        // 80 columns
"\n--------------------------------------------------------------------------------\n";
        d2::core::plain_text_explanation(std::cout, dl);
        std::cout << '\n';
    }

public:
    int run(int argc, char const* argv[]) {
        try {
            if (!parse_command_line(argc, argv))
                return EXIT_FAILURE;

            boost::shared_ptr<Skeleton> skeleton = create_skeleton();
            if (!skeleton)
                return EXIT_FAILURE;

            if (analyze)
                skeleton->on_deadlocks(print_deadlock);

            if (stats) {
                std::cout << boost::format(
                    "number of threads: %1%\n"
                    "number of distinct locks: %2%\n")
                    % skeleton->number_of_threads()
                    % skeleton->number_of_locks();
            }

        } catch (std::exception const& e) {
            error("unknown problem:");
            error(boost::diagnostic_information(e));
        }

        return EXIT_SUCCESS;
    }
};
} // end anonymous namespace

int main(int argc, char const* argv[]) {
    Driver driver;
    return driver.run(argc, argv);
}
<commit_msg>Change default values of the options in the utility.<commit_after>/**
 * This file implements a command line utility to interact
 * with the `d2` library.
 */

#include <boost/exception/diagnostic_information.hpp>
#include <boost/exception/get_error_info.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/format.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/make_shared.hpp>
#include <boost/program_options.hpp>
#include <boost/shared_ptr.hpp>
#include <cstdlib> // EXIT_FAILURE, EXIT_SUCCESS
#include <d2/core/diagnostic.hpp>
#include <d2/core/exceptions.hpp>
#include <d2/core/filesystem.hpp>
#include <d2/core/synchronization_skeleton.hpp>
#include <exception>
#include <iostream>
#include <string>

namespace {
namespace po = boost::program_options;

class Driver {
    /**
     * Return a string representation of the data associated to an `ErrorTag`.
     *
     * If no data associated to that tag is present in the exception object,
     * `default_` is returned instead.
     */
    template <typename ErrorTag, typename Exception>
    static std::string
    get_error_info(Exception const& e, std::string default_ = "unavailable") {
        typedef typename ErrorTag::value_type Info;
        Info const* info = boost::get_error_info<ErrorTag>(e);
        return info ? boost::lexical_cast<std::string>(*info) : default_;
    }

    typedef d2::core::synchronization_skeleton Skeleton;

    //! Print an error to the standard error stream with a trailing newline.
    template <typename Printable>
    static void error(Printable const& p) {
        std::cerr << "d2: error: " << p << '\n';
    }

    /**
     * Return a pointer to a `synchronization_skeleton` loaded with the data
     * found in the repository, or a default initialized `shared_ptr` if
     * anything goes wrong.
     */
    boost::shared_ptr<Skeleton> create_skeleton() const {
        if (!boost::filesystem::exists(repo)) {
            error(repo + " does not exist");
            return boost::shared_ptr<Skeleton>();
        }

        try {
            return boost::make_shared<Skeleton>(repo);

        } catch (d2::core::filesystem_error const& e) {
            error("unable to open the repository at " + repo);
            if (debug)
                error(boost::diagnostic_information(e));

        } catch (d2::EventTypeException const& e) {
            std::string actual_type = get_error_info<d2::ActualType>(e);
            std::string expected_type = get_error_info<d2::ExpectedType>(e);

            error(boost::format(
                    "while building the graphs:\n"
                    "    encountered an event of type %1%\n"
                    "    while expecting an event of type %2%")
                    % actual_type % expected_type);
            if (debug)
                error(boost::diagnostic_information(e));

        } catch (d2::UnexpectedReleaseException const& e) {
            std::string lock = get_error_info<d2::ReleasedLock>(e);
            std::string thread = get_error_info<d2::ReleasingThread>(e);

            error(boost::format(
                    "while building the graphs:\n"
                    "    lock %1% was unexpectedly released by thread %2%")
                    % lock % thread);

             if (debug)
                error(boost::diagnostic_information(e));
        }
        return boost::shared_ptr<Skeleton>();
    }

    bool parse_command_line(int argc, char const* argv[]) {
        po::variables_map args;
        po::options_description visible, hidden, all;
        po::positional_options_description positionals;
        bool help;

        visible.add_options()
        (
            "help,h",
            po::bool_switch(&help)->default_value(false, "false"),
            "produce help message and exit"
        )(
            "analyze",
            // See below; we'll give --analyze its real default value later.
            po::bool_switch(&analyze)->default_value(false,
                "enabled by default if --stats is not specified"),
            "perform the analysis for deadlocks"
        )(
            "stats",
            po::bool_switch(&stats)->default_value(false, "false"),
            "produce statistics about the usage of locks and threads"
        )(
            "debug",
            po::bool_switch(&debug)->default_value(false, "false"),
            "enable special debugging output"
        )
        ;

        hidden.add_options()
        (
            "repo-path",
            po::value<std::string>(&repo),
            "path of the repository to examine"
        )
        ;

        positionals.add("repo-path", 1);
        all.add(visible).add(hidden);

        po::command_line_parser parser(argc, argv);
        try {
            po::store(parser.options(all).positional(positionals).run(), args);
        } catch (po::error const& e) {
            error(e.what());
            return false;
        }
        po::notify(args);

        // If neither --stats nor --analyze is specified, --analyze is set
        // by default.
        if (!stats && !analyze)
            analyze = true;

        if (help) {
            std::cout << visible;
            return false;
        }

        if (repo.empty()) {
            error("missing input directory");
            return false;
        }

        return true;
    }

    std::string repo;
    bool debug, analyze, stats;

    static void print_deadlock(d2::core::potential_deadlock const& dl) {
        std::cout <<
        // 80 columns
"\n--------------------------------------------------------------------------------\n";
        d2::core::plain_text_explanation(std::cout, dl);
        std::cout << '\n';
    }

public:
    int run(int argc, char const* argv[]) {
        try {
            if (!parse_command_line(argc, argv))
                return EXIT_FAILURE;

            boost::shared_ptr<Skeleton> skeleton = create_skeleton();
            if (!skeleton)
                return EXIT_FAILURE;

            if (analyze)
                skeleton->on_deadlocks(print_deadlock);

            if (stats) {
                std::cout << boost::format(
                    "number of threads: %1%\n"
                    "number of distinct locks: %2%\n")
                    % skeleton->number_of_threads()
                    % skeleton->number_of_locks();
            }

        } catch (std::exception const& e) {
            error("unknown problem:");
            error(boost::diagnostic_information(e));
            return EXIT_FAILURE;
        }

        return EXIT_SUCCESS;
    }
};
} // end anonymous namespace

int main(int argc, char const* argv[]) {
    Driver driver;
    return driver.run(argc, argv);
}
<|endoftext|>