<commit_before>#include "libxtreemfs/object_cache.h"

#include <stdint.h>

#include <boost/optional.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/mutex.hpp>
#include <gtest/gtest_prod.h>
#include <list>
#include <map>
#include <string>

#include "xtreemfs/OSD.pb.h"
#include "rpc/sync_callback.h"

namespace xtreemfs {

static uint64_t Now() {
  return time(NULL);
}

CachedObject::CachedObject(int object_no, int object_size)
    : object_no_(object_no), object_size_(object_size),
      data_(NULL), actual_size_(0), is_dirty_(false),
      last_access_(Now()) {}

CachedObject::~CachedObject() {
  delete [] data_;
}

// Flush data and free memory
void CachedObject::Erase(const ObjectWriterCb& writer) {
  boost::unique_lock<boost::mutex> lock(mutex_);
  if (is_dirty_) {
    WriteObjectToOSD(writer);
    DropLocked();
  }
}

void CachedObject::Drop() {
  boost::unique_lock<boost::mutex> lock(mutex_);
  DropLocked();
}

void CachedObject::DropLocked() {
  is_dirty_ = false;
  actual_size_ = 0;
  delete [] data_;
  data_ = NULL;
}

int CachedObject::Read(int offset_in_object, char* buffer, int bytes_to_read,
                       const ObjectReaderCb& reader) {
  boost::unique_lock<boost::mutex> lock(mutex_);
  ReadInternal(lock, reader);
  int actual_bytes = std::min(bytes_to_read, actual_size_ - offset_in_object);
  memcpy(buffer, &data_[offset_in_object], actual_bytes);
  last_access_ = Now();
  return actual_bytes;
}

void CachedObject::Write(int offset_in_object, const char* buffer,
                         int bytes_to_write, const ObjectReaderCb& reader) {
  boost::unique_lock<boost::mutex> lock(mutex_);
  ReadInternal(lock, reader);
  memcpy(data_, &buffer[offset_in_object], bytes_to_write);
  actual_size_ = std::max(actual_size_, offset_in_object + bytes_to_write);
  is_dirty_ = true;
  last_access_ = Now();
}

void CachedObject::Flush(const ObjectWriterCb& writer) {
  boost::unique_lock<boost::mutex> lock(mutex_);
  if (is_dirty_) {
    // Write out a copy of the data asynchronously.
    WriteObjectToOSD(writer);
    is_dirty_ = false;
    // Other threads can continue to work with the buffer.
    // Another flush can happen in the meantime.
  }
}

void CachedObject::Truncate(int new_object_size) {
  boost::unique_lock<boost::mutex> lock(mutex_);
  if (actual_size_ == new_object_size) {
    return;
  }
  if (actual_size_ < new_object_size) {
    memset(&data_[actual_size_], 0, new_object_size - actual_size_);
  }
  actual_size_ = new_object_size;
  is_dirty_ = true;
}

uint64_t CachedObject::last_access() {
  boost::unique_lock<boost::mutex> lock(mutex_);
  return last_access_;
}

bool CachedObject::is_dirty() {
  boost::unique_lock<boost::mutex> lock(mutex_);
  return is_dirty_;
}

void CachedObject::ReadInternal(boost::unique_lock<boost::mutex>& lock,
                               const ObjectReaderCb& reader) {
  if (ReadPending()) {
    if (read_queue_.size() == 0) {
      // Initial read
      ReadObjectFromOSD(lock, reader);  // unlocked synchronous read.
    } else {
      // Read already initiated
      boost::condition_variable* v = new boost::condition_variable();
      read_queue_.push_back(v);
      v->wait(lock);  // unlocks mutex
      delete v;  // has been dequeued already by our predecessor
    }
  }

  // We are done, next in line please.
  // It will enter when we release the lock, and wake up its successor.
  if (read_queue_.size() > 0) {
    boost::condition_variable* v = read_queue_.front();
    read_queue_.pop_front();
    v->notify_one();
  }
}

void CachedObject::ReadObjectFromOSD(boost::unique_lock<boost::mutex>& lock,
                                     const ObjectReaderCb& reader) {
  lock.unlock();
  char* data = new char[object_size_];
  int read = reader(object_no_, data);
  lock.lock();

  data_ = data;
  actual_size_ = read;
}

void CachedObject::WriteObjectToOSD(const ObjectWriterCb& writer) {
  writer(object_no_, data_, actual_size_);
}

bool CachedObject::ReadPending() {
  return data_ == NULL;
}

ObjectCache::ObjectCache(size_t max_objects, int object_size)
  : max_objects_(max_objects), object_size_(object_size) {
}

ObjectCache::~ObjectCache() {
  for (Cache::iterator i = cache_.begin(); i != cache_.end(); ++i) {
    delete i->second;
  }
}

int ObjectCache::Read(int object_no, int offset_in_object,
                      char* buffer, int bytes_to_read,
                      const ObjectReaderCb& reader,
                      const ObjectWriterCb& writer) {
  assert(bytes_to_read + offset_in_object <= object_size_);
  CachedObject* object = LookupObject(object_no, writer);
  return object->Read(offset_in_object, buffer, bytes_to_read, reader);
}

void ObjectCache::Write(int object_no, int offset_in_object,
                        const char* buffer, int bytes_to_write,
                        const ObjectReaderCb& reader,
                        const ObjectWriterCb& writer) {
  assert(bytes_to_write + offset_in_object <= object_size_);
  CachedObject* object = LookupObject(object_no, writer);
  object->Write(offset_in_object, buffer, bytes_to_write, reader);
}

void ObjectCache::Flush(const ObjectWriterCb& writer) {
  while (true) {
    boost::unique_lock<boost::mutex> lock(mutex_);
    Cache::iterator i;
    for (i = cache_.begin(); i != cache_.end(); ++i) {
      if (i->second->is_dirty()) {
        CachedObject* object = i->second;
        lock.unlock();
        object->Flush(writer);
        break;  // start from beginning
      }
    }
    if (i == cache_.end()) {
      break;
    }
  }
}

void ObjectCache::Truncate(int64_t new_size) {
  boost::unique_lock<boost::mutex> lock(mutex_);
  int object_to_cut = static_cast<int>(new_size / object_size_);
  for (Cache::iterator i = cache_.begin(); i != cache_.end(); ++i) {
    if (i->first == object_to_cut) {
      i->second->Truncate(new_size % object_size_);
    } else if (i->first < object_to_cut) {
      i->second->Truncate(object_size_);
    } else if (i->first > object_to_cut) {
      i->second->Drop();
    }
  }
}

CachedObject* ObjectCache::LookupObject(int object_no,
                                        const ObjectWriterCb& writer) {
  boost::unique_lock<boost::mutex> lock(mutex_);
  Cache::iterator i = cache_.find(object_no);
  if (i == cache_.end()) {
    cache_[object_no] = new CachedObject(object_no, object_size_);

    if (cache_.size() > max_objects_) {
      CollectLeasedObject(writer);
    }
  }
  return cache_[object_no];
}

void ObjectCache::CollectLeasedObject(const ObjectWriterCb& writer) {
  uint64_t minimum_atime = UINT64_MAX;
  Cache::iterator min;
  for (Cache::iterator i = cache_.begin(); i != cache_.end(); ++i) {
    if (minimum_atime > i->second->last_access()) {
      min = i;
      minimum_atime = i->second->last_access();
    }
  }
  assert(min != cache_.end());
  min->second->Erase(writer);
}

int ObjectCache::object_size() const {
  return object_size_;
}

}  // namespace xtreemfs
<commit_msg>Compilation fix<commit_after>#include "libxtreemfs/object_cache.h"

#include <stdint.h>

#include <boost/optional.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/mutex.hpp>
#include <gtest/gtest_prod.h>
#include <list>
#include <map>
#include <string>

#include "xtreemfs/OSD.pb.h"
#include "rpc/sync_callback.h"

namespace xtreemfs {

static uint64_t Now() {
  return time(NULL);
}

CachedObject::CachedObject(int object_no, int object_size)
    : object_no_(object_no), object_size_(object_size),
      data_(NULL), actual_size_(0), is_dirty_(false),
      last_access_(Now()) {}

CachedObject::~CachedObject() {
  delete [] data_;
}

// Flush data and free memory
void CachedObject::Erase(const ObjectWriterCb& writer) {
  boost::unique_lock<boost::mutex> lock(mutex_);
  if (is_dirty_) {
    WriteObjectToOSD(writer);
    DropLocked();
  }
}

void CachedObject::Drop() {
  boost::unique_lock<boost::mutex> lock(mutex_);
  DropLocked();
}

void CachedObject::DropLocked() {
  is_dirty_ = false;
  actual_size_ = 0;
  delete [] data_;
  data_ = NULL;
}

int CachedObject::Read(int offset_in_object, char* buffer, int bytes_to_read,
                       const ObjectReaderCb& reader) {
  boost::unique_lock<boost::mutex> lock(mutex_);
  ReadInternal(lock, reader);
  int actual_bytes = std::min(bytes_to_read, actual_size_ - offset_in_object);
  memcpy(buffer, &data_[offset_in_object], actual_bytes);
  last_access_ = Now();
  return actual_bytes;
}

void CachedObject::Write(int offset_in_object, const char* buffer,
                         int bytes_to_write, const ObjectReaderCb& reader) {
  boost::unique_lock<boost::mutex> lock(mutex_);
  ReadInternal(lock, reader);
  memcpy(data_, &buffer[offset_in_object], bytes_to_write);
  actual_size_ = std::max(actual_size_, offset_in_object + bytes_to_write);
  is_dirty_ = true;
  last_access_ = Now();
}

void CachedObject::Flush(const ObjectWriterCb& writer) {
  boost::unique_lock<boost::mutex> lock(mutex_);
  if (is_dirty_) {
    // Write out a copy of the data asynchronously.
    WriteObjectToOSD(writer);
    is_dirty_ = false;
    // Other threads can continue to work with the buffer.
    // Another flush can happen in the meantime.
  }
}

void CachedObject::Truncate(int new_object_size) {
  boost::unique_lock<boost::mutex> lock(mutex_);
  if (actual_size_ == new_object_size) {
    return;
  }
  if (actual_size_ < new_object_size) {
    memset(&data_[actual_size_], 0, new_object_size - actual_size_);
  }
  actual_size_ = new_object_size;
  is_dirty_ = true;
}

uint64_t CachedObject::last_access() {
  boost::unique_lock<boost::mutex> lock(mutex_);
  return last_access_;
}

bool CachedObject::is_dirty() {
  boost::unique_lock<boost::mutex> lock(mutex_);
  return is_dirty_;
}

void CachedObject::ReadInternal(boost::unique_lock<boost::mutex>& lock,
                               const ObjectReaderCb& reader) {
  if (ReadPending()) {
    if (read_queue_.size() == 0) {
      // Initial read
      ReadObjectFromOSD(lock, reader);  // unlocked synchronous read.
    } else {
      // Read already initiated
      boost::condition_variable* v = new boost::condition_variable();
      read_queue_.push_back(v);
      v->wait(lock);  // unlocks mutex
      delete v;  // has been dequeued already by our predecessor
    }
  }

  // We are done, next in line please.
  // It will enter when we release the lock, and wake up its successor.
  if (read_queue_.size() > 0) {
    boost::condition_variable* v = read_queue_.front();
    read_queue_.pop_front();
    v->notify_one();
  }
}

void CachedObject::ReadObjectFromOSD(boost::unique_lock<boost::mutex>& lock,
                                     const ObjectReaderCb& reader) {
  lock.unlock();
  char* data = new char[object_size_];
  int read = reader(object_no_, data);
  lock.lock();

  data_ = data;
  actual_size_ = read;
}

void CachedObject::WriteObjectToOSD(const ObjectWriterCb& writer) {
  writer(object_no_, data_, actual_size_);
}

bool CachedObject::ReadPending() {
  return data_ == NULL;
}

ObjectCache::ObjectCache(size_t max_objects, int object_size)
  : max_objects_(max_objects), object_size_(object_size) {
}

ObjectCache::~ObjectCache() {
  for (Cache::iterator i = cache_.begin(); i != cache_.end(); ++i) {
    delete i->second;
  }
}

int ObjectCache::Read(int object_no, int offset_in_object,
                      char* buffer, int bytes_to_read,
                      const ObjectReaderCb& reader,
                      const ObjectWriterCb& writer) {
  assert(bytes_to_read + offset_in_object <= object_size_);
  CachedObject* object = LookupObject(object_no, writer);
  return object->Read(offset_in_object, buffer, bytes_to_read, reader);
}

void ObjectCache::Write(int object_no, int offset_in_object,
                        const char* buffer, int bytes_to_write,
                        const ObjectReaderCb& reader,
                        const ObjectWriterCb& writer) {
  assert(bytes_to_write + offset_in_object <= object_size_);
  CachedObject* object = LookupObject(object_no, writer);
  object->Write(offset_in_object, buffer, bytes_to_write, reader);
}

void ObjectCache::Flush(const ObjectWriterCb& writer) {
  while (true) {
    boost::unique_lock<boost::mutex> lock(mutex_);
    Cache::iterator i;
    for (i = cache_.begin(); i != cache_.end(); ++i) {
      if (i->second->is_dirty()) {
        CachedObject* object = i->second;
        lock.unlock();
        object->Flush(writer);
        break;  // start from beginning
      }
    }
    if (i == cache_.end()) {
      break;
    }
  }
}

void ObjectCache::Truncate(int64_t new_size) {
  boost::unique_lock<boost::mutex> lock(mutex_);
  int object_to_cut = static_cast<int>(new_size / object_size_);
  for (Cache::iterator i = cache_.begin(); i != cache_.end(); ++i) {
    if (i->first == object_to_cut) {
      i->second->Truncate(new_size % object_size_);
    } else if (i->first < object_to_cut) {
      i->second->Truncate(object_size_);
    } else if (i->first > object_to_cut) {
      i->second->Drop();
    }
  }
}

CachedObject* ObjectCache::LookupObject(int object_no,
                                        const ObjectWriterCb& writer) {
  boost::unique_lock<boost::mutex> lock(mutex_);
  Cache::iterator i = cache_.find(object_no);
  if (i == cache_.end()) {
    cache_[object_no] = new CachedObject(object_no, object_size_);

    if (cache_.size() > max_objects_) {
      CollectLeasedObject(writer);
    }
  }
  return cache_[object_no];
}

void ObjectCache::CollectLeasedObject(const ObjectWriterCb& writer) {
  uint64_t minimum_atime = std::numeric_limits<uint64_t>::max();
  Cache::iterator min;
  for (Cache::iterator i = cache_.begin(); i != cache_.end(); ++i) {
    if (minimum_atime > i->second->last_access()) {
      min = i;
      minimum_atime = i->second->last_access();
    }
  }
  assert(min != cache_.end());
  min->second->Erase(writer);
}

int ObjectCache::object_size() const {
  return object_size_;
}

}  // namespace xtreemfs
<|endoftext|>


<commit_before>/** Copyright (C) 2016, 2017 European Spallation Source ERIC */

#include <cassert>
#include <common/Trace.h>
#include <nmxvmm2srs/EventletBuilder.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

EventletBuilder::EventletBuilder(Time time_intepreter,
                                 Geometry geometry_interpreter)
    : time_intepreter_(time_intepreter),
      geometry_interpreter_(geometry_interpreter) {
#ifdef DUMPTOFILE
        //std::string fileName = "dumpfile_"
        fd = open("dumpfile.txt", O_RDWR|O_CREAT, S_IRWXU);
        assert(fd >= 0);
        time_t t = time(NULL);
        struct tm * tm = localtime(&t);
        char s[128];
        strftime(s, sizeof(s), "%c", tm);
        dprintf(fd, "%s\n", s);
        dprintf(fd, "# fec, chip_id, srs timestamp, channel, bcid, tdc, adc\n");
#endif
      }

uint32_t EventletBuilder::process_readout(NMXVMM2SRSData &data, Clusterer &clusterer) {
  uint16_t fec_id = 1;                         /**< @todo not hardcode */
  uint16_t chip_id = data.srshdr.dataid & 0xf; /**< @todo may belong elswhere */

  Eventlet eventlet;
  for (unsigned int i = 0; i < data.elems; i++) {
    auto & d = data.data[i];
    XTRACE(PROCESS, DEB, "eventlet timestamp: hi 0x%08x, lo: 0x%08x\n",
           data.srshdr.time, (d.bcid << 16) + d.tdc);
    XTRACE(PROCESS, DEB, "eventlet  chip: %d, channel: %d\n", chip_id, d.chno);
    eventlet.time = time_intepreter_.timestamp(data.srshdr.time, d.bcid, d.tdc);
    eventlet.plane_id = geometry_interpreter_.get_plane(fec_id, chip_id);
    eventlet.strip = geometry_interpreter_.get_strip(fec_id, chip_id, d.chno);
    eventlet.adc = d.adc;
    XTRACE(PROCESS, DEB, "eventlet  plane_id: %d, strip: %d\n", eventlet.plane_id, eventlet.strip);
    /**< @todo flags? */

#ifdef DUMPTOFILE
    dprintf(fd, "%2d, %2d, %u, %2d, %d, %d\n",
            1, chip_id, data.srshdr.time, d.chno, d.bcid, d.tdc, d.adc);
#endif

    assert(eventlet.plane_id == 0 || eventlet.plane_id == 1);
    assert(eventlet.strip <= 1500);
    data.xyhist[eventlet.plane_id][eventlet.strip]++;
    data.xyhist_elems++;
    clusterer.insert(eventlet);
  }

  return data.elems;
}
<commit_msg>Corrected format specifier mistake<commit_after>/** Copyright (C) 2016, 2017 European Spallation Source ERIC */

#include <cassert>
#include <common/Trace.h>
#include <nmxvmm2srs/EventletBuilder.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

EventletBuilder::EventletBuilder(Time time_intepreter,
                                 Geometry geometry_interpreter)
    : time_intepreter_(time_intepreter),
      geometry_interpreter_(geometry_interpreter) {
#ifdef DUMPTOFILE
        //std::string fileName = "dumpfile_"
        fd = open("dumpfile.txt", O_RDWR|O_CREAT, S_IRWXU);
        assert(fd >= 0);
        time_t t = time(NULL);
        struct tm * tm = localtime(&t);
        char s[128];
        strftime(s, sizeof(s), "%c", tm);
        dprintf(fd, "%s\n", s);
        dprintf(fd, "# fec, chip_id, srs timestamp, channel, bcid, tdc, adc\n");
#endif
      }

uint32_t EventletBuilder::process_readout(NMXVMM2SRSData &data, Clusterer &clusterer) {
  uint16_t fec_id = 1;                         /**< @todo not hardcode */
  uint16_t chip_id = data.srshdr.dataid & 0xf; /**< @todo may belong elswhere */

  Eventlet eventlet;
  for (unsigned int i = 0; i < data.elems; i++) {
    auto & d = data.data[i];
    XTRACE(PROCESS, DEB, "eventlet timestamp: hi 0x%08x, lo: 0x%08x\n",
           data.srshdr.time, (d.bcid << 16) + d.tdc);
    XTRACE(PROCESS, DEB, "eventlet  chip: %d, channel: %d\n", chip_id, d.chno);
    eventlet.time = time_intepreter_.timestamp(data.srshdr.time, d.bcid, d.tdc);
    eventlet.plane_id = geometry_interpreter_.get_plane(fec_id, chip_id);
    eventlet.strip = geometry_interpreter_.get_strip(fec_id, chip_id, d.chno);
    eventlet.adc = d.adc;
    XTRACE(PROCESS, DEB, "eventlet  plane_id: %d, strip: %d\n", eventlet.plane_id, eventlet.strip);
    /**< @todo flags? */

#ifdef DUMPTOFILE
    dprintf(fd, "%2d, %2d, %u, %2d, %d, %d, %d\n",
            1, chip_id, data.srshdr.time, d.chno, d.bcid, d.tdc, d.adc);
#endif

    assert(eventlet.plane_id == 0 || eventlet.plane_id == 1);
    assert(eventlet.strip <= 1500);
    data.xyhist[eventlet.plane_id][eventlet.strip]++;
    data.xyhist_elems++;
    clusterer.insert(eventlet);
  }

  return data.elems;
}
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "pcl/gpu/common/device_array.hpp"
#include "pcl/gpu/common/safe_call.hpp"

#include "cuda_runtime_api.h"

//////////////////////////    XADD    ///////////////////////////////

#ifdef __GNUC__

    #if __GNUC__*10 + __GNUC_MINOR__ >= 42

        #if !defined WIN32 && (defined __i486__ || defined __i586__ || defined __i686__ || defined __MMX__ || defined __SSE__  || defined __ppc__)
            #define CV_XADD __sync_fetch_and_add
        #else
            #include <ext/atomicity.h>
            #define CV_XADD __gnu_cxx::__exchange_and_add
        #endif
    #else
        #include <bits/atomicity.h>
        #if __GNUC__*10 + __GNUC_MINOR__ >= 34
            #define CV_XADD __gnu_cxx::__exchange_and_add
        #else
            #define CV_XADD __exchange_and_add
        #endif
  #endif

#elif defined WIN32 || defined _WIN32
    #include <intrin.h>
    #define CV_XADD(addr,delta) _InterlockedExchangeAdd((long volatile*)(addr), (delta))
#else

    template<typename _Tp> static inline _Tp CV_XADD(_Tp* addr, _Tp delta)
    { int tmp = *addr; *addr += delta; return tmp; }

#endif

////////////////////////    DeviceArray    /////////////////////////////

pcl::gpu::DeviceArray::DeviceArray() : data_(0), size_(0), refcount_(0) {}
pcl::gpu::DeviceArray::DeviceArray(void *ptr, size_t size) : data_(ptr), size_(size), refcount_(0) {}
pcl::gpu::DeviceArray::DeviceArray(size_t size)  : data_(0), size_(0), refcount_(0)  { create(size_); }
pcl::gpu::DeviceArray::~DeviceArray() { release(); }

pcl::gpu::DeviceArray::DeviceArray(const DeviceArray& other) : data_(other.data_), size_(other.size_), refcount_(other.refcount_)
{
    if( refcount_ )
        CV_XADD(refcount_, 1);
}

pcl::gpu::DeviceArray& pcl::gpu::DeviceArray::operator = (const pcl::gpu::DeviceArray& other)
{
    if( this != &other )
    {
        if( other.refcount_ )
            CV_XADD(other.refcount_, 1);
        release();

        data_ = other.data_;
        size_ = other.size_;
        refcount_ = other.refcount_;
    }
    return *this;
}

void pcl::gpu::DeviceArray::create(size_t size)
{
    if (size_ == size)
        return;

    if( size > 0)
    {
        if( data_ )
            release();

        size_ = size;

        cudaSafeCall( cudaMalloc(&data_, size_) );

        //refcount_ = (int*)cv::fastMalloc(sizeof(*refcount_));
        refcount_ = new int;
        *refcount_ = 1;
    }
}

void pcl::gpu::DeviceArray::release()
{
    if( refcount_ && CV_XADD(refcount_, -1) == 1 )
    {
        //cv::fastFree(refcount_);
        delete refcount_;
        cudaSafeCall( cudaFree(data_) );
    }
    data_ = 0;
    size_ = 0;
    refcount_ = 0;
}

void pcl::gpu::DeviceArray::upload(const void *host_ptr, size_t size)
{
    create(size);
    cudaSafeCall( cudaMemcpy(data_, host_ptr, size_, cudaMemcpyHostToDevice) );
}

void pcl::gpu::DeviceArray::download(void *host_ptr) const
{
    cudaSafeCall( cudaMemcpy(host_ptr, data_, size_, cudaMemcpyDeviceToHost) );
}

size_t pcl::gpu::DeviceArray::sizeBytes() const { return size_; }

////////////////////////    DeviceArray2D    /////////////////////////////

pcl::gpu::DeviceArray2D::DeviceArray2D() : colsBytes_(0), rows_(0), data_(0), step_(0), refcount_(0) {}

pcl::gpu::DeviceArray2D::DeviceArray2D(int rows, int colsBytes)
    : colsBytes_(0), rows_(0), data_(0), step_(0), refcount_(0)
{
    create(rows, colsBytes);
}

pcl::gpu::DeviceArray2D::DeviceArray2D(int rows, int colsBytes, void *data, size_t stepBytes)
    : colsBytes_(colsBytes), rows_(rows), data_((char*)data), step_(stepBytes), refcount_(0) {}

pcl::gpu::DeviceArray2D::~DeviceArray2D() { release(); }

pcl::gpu::DeviceArray2D::DeviceArray2D(const DeviceArray2D& other) :
    colsBytes_(other.colsBytes_), rows_(other.rows_), data_(other.data_), step_(other.step_), refcount_(other.refcount_)
{
    if( refcount_ )
        CV_XADD(refcount_, 1);
}

pcl::gpu::DeviceArray2D& pcl::gpu::DeviceArray2D::operator = (const pcl::gpu::DeviceArray2D& other)
{
    if( this != &other )
    {
        if( other.refcount_ )
            CV_XADD(other.refcount_, 1);
        release();

        colsBytes_ = other.colsBytes_;
        rows_ = other.rows_;
        data_ = other.data_;
        step_ = other.step_;

        refcount_ = other.refcount_;
    }
    return *this;
}

void pcl::gpu::DeviceArray2D::create(int rows, int colsBytes)
{
    if (colsBytes_ == colsBytes && rows_ == rows)
        return;

    if( rows > 0 && colsBytes > 0)
    {
        if( data_ )
            release();

        colsBytes = colsBytes;
        rows_ = rows;

        cudaSafeCall( cudaMallocPitch( (void**)&data_, &step_, colsBytes, rows) );

        //refcount_ = (int*)cv::fastMalloc(sizeof(*refcount_));
        refcount_ = new int;
        *refcount_ = 1;
    }
}

void pcl::gpu::DeviceArray2D::release()
{
    if( refcount_ && CV_XADD(refcount_, -1) == 1 )
    {
        //cv::fastFree(refcount_);
        delete refcount_;
        cudaSafeCall( cudaFree(data_) );
    }

    colsBytes_ = 0;
    rows_ = 0;
    data_ = 0;
    step_ = 0;
    refcount_ = 0;
}

void pcl::gpu::DeviceArray2D::upload(const void *host_ptr, size_t host_step, int rows, int colsBytes)
{
    create(rows, colsBytes);
    cudaSafeCall( cudaMemcpy2D(data_, step_, host_ptr, host_step, colsBytes_, rows_, cudaMemcpyHostToDevice) );
}

void pcl::gpu::DeviceArray2D::download(void *host_ptr, size_t host_step) const
{
    cudaSafeCall( cudaMemcpy2D(host_ptr, host_step, data_, step_, colsBytes_, rows_, cudaMemcpyDeviceToHost) );
}

size_t pcl::gpu::DeviceArray2D::step() const { return step_; }
int pcl::gpu::DeviceArray2D::colsBytes() const { return colsBytes_; }
int pcl::gpu::DeviceArray2D::rows() const { return rows_; }

<commit_msg>fixed bug in device_array<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Copyright (c) 2011, Willow Garage, Inc.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "pcl/gpu/common/device_array.hpp"
#include "pcl/gpu/common/safe_call.hpp"

#include "cuda_runtime_api.h"

//////////////////////////    XADD    ///////////////////////////////

#ifdef __GNUC__

    #if __GNUC__*10 + __GNUC_MINOR__ >= 42

        #if !defined WIN32 && (defined __i486__ || defined __i586__ || defined __i686__ || defined __MMX__ || defined __SSE__  || defined __ppc__)
            #define CV_XADD __sync_fetch_and_add
        #else
            #include <ext/atomicity.h>
            #define CV_XADD __gnu_cxx::__exchange_and_add
        #endif
    #else
        #include <bits/atomicity.h>
        #if __GNUC__*10 + __GNUC_MINOR__ >= 34
            #define CV_XADD __gnu_cxx::__exchange_and_add
        #else
            #define CV_XADD __exchange_and_add
        #endif
  #endif

#elif defined WIN32 || defined _WIN32
    #include <intrin.h>
    #define CV_XADD(addr,delta) _InterlockedExchangeAdd((long volatile*)(addr), (delta))
#else

    template<typename _Tp> static inline _Tp CV_XADD(_Tp* addr, _Tp delta)
    { int tmp = *addr; *addr += delta; return tmp; }

#endif

////////////////////////    DeviceArray    /////////////////////////////

pcl::gpu::DeviceArray::DeviceArray() : data_(0), size_(0), refcount_(0) {}
pcl::gpu::DeviceArray::DeviceArray(void *ptr, size_t size) : data_(ptr), size_(size), refcount_(0) {}
pcl::gpu::DeviceArray::DeviceArray(size_t size)  : data_(0), size_(0), refcount_(0)  { create(size); }
pcl::gpu::DeviceArray::~DeviceArray() { release(); }

pcl::gpu::DeviceArray::DeviceArray(const DeviceArray& other) : data_(other.data_), size_(other.size_), refcount_(other.refcount_)
{
    if( refcount_ )
        CV_XADD(refcount_, 1);
}

pcl::gpu::DeviceArray& pcl::gpu::DeviceArray::operator = (const pcl::gpu::DeviceArray& other)
{
    if( this != &other )
    {
        if( other.refcount_ )
            CV_XADD(other.refcount_, 1);
        release();

        data_ = other.data_;
        size_ = other.size_;
        refcount_ = other.refcount_;
    }
    return *this;
}

void pcl::gpu::DeviceArray::create(size_t size)
{
    if (size_ == size)
        return;

    if( size > 0)
    {
        if( data_ )
            release();

        size_ = size;

        cudaSafeCall( cudaMalloc(&data_, size_) );

        //refcount_ = (int*)cv::fastMalloc(sizeof(*refcount_));
        refcount_ = new int;
        *refcount_ = 1;
    }
}

void pcl::gpu::DeviceArray::release()
{
    if( refcount_ && CV_XADD(refcount_, -1) == 1 )
    {
        //cv::fastFree(refcount_);
        delete refcount_;
        cudaSafeCall( cudaFree(data_) );
    }
    data_ = 0;
    size_ = 0;
    refcount_ = 0;
}

void pcl::gpu::DeviceArray::upload(const void *host_ptr, size_t size)
{
    create(size);
    cudaSafeCall( cudaMemcpy(data_, host_ptr, size_, cudaMemcpyHostToDevice) );
}

void pcl::gpu::DeviceArray::download(void *host_ptr) const
{
    cudaSafeCall( cudaMemcpy(host_ptr, data_, size_, cudaMemcpyDeviceToHost) );
}

size_t pcl::gpu::DeviceArray::sizeBytes() const { return size_; }

////////////////////////    DeviceArray2D    /////////////////////////////

pcl::gpu::DeviceArray2D::DeviceArray2D() : colsBytes_(0), rows_(0), data_(0), step_(0), refcount_(0) {}

pcl::gpu::DeviceArray2D::DeviceArray2D(int rows, int colsBytes)
    : colsBytes_(0), rows_(0), data_(0), step_(0), refcount_(0)
{
    create(rows, colsBytes);
}

pcl::gpu::DeviceArray2D::DeviceArray2D(int rows, int colsBytes, void *data, size_t stepBytes)
    : colsBytes_(colsBytes), rows_(rows), data_((char*)data), step_(stepBytes), refcount_(0) {}

pcl::gpu::DeviceArray2D::~DeviceArray2D() { release(); }

pcl::gpu::DeviceArray2D::DeviceArray2D(const DeviceArray2D& other) :
    colsBytes_(other.colsBytes_), rows_(other.rows_), data_(other.data_), step_(other.step_), refcount_(other.refcount_)
{
    if( refcount_ )
        CV_XADD(refcount_, 1);
}

pcl::gpu::DeviceArray2D& pcl::gpu::DeviceArray2D::operator = (const pcl::gpu::DeviceArray2D& other)
{
    if( this != &other )
    {
        if( other.refcount_ )
            CV_XADD(other.refcount_, 1);
        release();

        colsBytes_ = other.colsBytes_;
        rows_ = other.rows_;
        data_ = other.data_;
        step_ = other.step_;

        refcount_ = other.refcount_;
    }
    return *this;
}

void pcl::gpu::DeviceArray2D::create(int rows, int colsBytes)
{
    if (colsBytes_ == colsBytes && rows_ == rows)
        return;

    if( rows > 0 && colsBytes > 0)
    {
        if( data_ )
            release();

        colsBytes_ = colsBytes;
        rows_ = rows;

        cudaSafeCall( cudaMallocPitch( (void**)&data_, &step_, colsBytes, rows) );

        //refcount_ = (int*)cv::fastMalloc(sizeof(*refcount_));
        refcount_ = new int;
        *refcount_ = 1;
    }
}

void pcl::gpu::DeviceArray2D::release()
{
    if( refcount_ && CV_XADD(refcount_, -1) == 1 )
    {
        //cv::fastFree(refcount_);
        delete refcount_;
        cudaSafeCall( cudaFree(data_) );
    }

    colsBytes_ = 0;
    rows_ = 0;
    data_ = 0;
    step_ = 0;
    refcount_ = 0;
}

void pcl::gpu::DeviceArray2D::upload(const void *host_ptr, size_t host_step, int rows, int colsBytes)
{
    create(rows, colsBytes);
    cudaSafeCall( cudaMemcpy2D(data_, step_, host_ptr, host_step, colsBytes_, rows_, cudaMemcpyHostToDevice) );
}

void pcl::gpu::DeviceArray2D::download(void *host_ptr, size_t host_step) const
{
    cudaSafeCall( cudaMemcpy2D(host_ptr, host_step, data_, step_, colsBytes_, rows_, cudaMemcpyDeviceToHost) );
}

size_t pcl::gpu::DeviceArray2D::step() const { return step_; }
int pcl::gpu::DeviceArray2D::colsBytes() const { return colsBytes_; }
int pcl::gpu::DeviceArray2D::rows() const { return rows_; }

<|endoftext|>


<commit_before>// Copyright 2019 The clvk authors.
//
// 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.

#define CL_USE_DEPRECATED_OPENCL_1_1_APIS

#include "testcl.hpp"

TEST_F(WithContext, CreateImageLegacy) {
    cl_image_format format = {CL_RGBA, CL_UNORM_INT8};

    size_t width = 97, height = 135, depth = 7;
    size_t row_pitch = 128, slice_pitch = row_pitch * height;

    cl_int err;

    // Create 2D image
    auto im2d = clCreateImage2D(m_context, CL_MEM_READ_WRITE, &format, width,
                                height, row_pitch, nullptr, &err);
    ASSERT_CL_SUCCESS(err);

    size_t qval;
    cl_image_format qfmt;

    // Query its properties
    GetImageInfo(im2d, CL_IMAGE_WIDTH, sizeof(qval), &qval, nullptr);
    EXPECT_EQ(qval, width);
    GetImageInfo(im2d, CL_IMAGE_HEIGHT, sizeof(qval), &qval, nullptr);
    EXPECT_EQ(qval, height);
    GetImageInfo(im2d, CL_IMAGE_ROW_PITCH, sizeof(qval), &qval, nullptr);
    EXPECT_EQ(qval, row_pitch);
    GetImageInfo(im2d, CL_IMAGE_FORMAT, sizeof(qfmt), &qfmt, nullptr);
    EXPECT_EQ(qfmt.image_channel_order, format.image_channel_order);
    EXPECT_EQ(qfmt.image_channel_data_type, format.image_channel_data_type);

    cl_mem_object_type qtype;
    GetMemObjectInfo(im2d, CL_MEM_TYPE, sizeof(qtype), &qtype, nullptr);
    EXPECT_EQ(qtype, CL_MEM_OBJECT_IMAGE2D);

    // Do the same for 3D images
    auto im3d =
        clCreateImage3D(m_context, CL_MEM_READ_WRITE, &format, width, height,
                        depth, row_pitch, slice_pitch, nullptr, &err);
    ASSERT_CL_SUCCESS(err);
    GetImageInfo(im3d, CL_IMAGE_WIDTH, sizeof(qval), &qval, nullptr);
    EXPECT_EQ(qval, width);
    GetImageInfo(im3d, CL_IMAGE_HEIGHT, sizeof(qval), &qval, nullptr);
    EXPECT_EQ(qval, height);
    GetImageInfo(im3d, CL_IMAGE_DEPTH, sizeof(qval), &qval, nullptr);
    EXPECT_EQ(qval, depth);
    GetImageInfo(im3d, CL_IMAGE_ROW_PITCH, sizeof(qval), &qval, nullptr);
    EXPECT_EQ(qval, row_pitch);
    GetImageInfo(im3d, CL_IMAGE_SLICE_PITCH, sizeof(qval), &qval, nullptr);
    EXPECT_EQ(qval, slice_pitch);
    GetImageInfo(im3d, CL_IMAGE_FORMAT, sizeof(qfmt), &qfmt, nullptr);
    EXPECT_EQ(qfmt.image_channel_order, format.image_channel_order);
    EXPECT_EQ(qfmt.image_channel_data_type, format.image_channel_data_type);

    GetMemObjectInfo(im3d, CL_MEM_TYPE, sizeof(qtype), &qtype, nullptr);
    EXPECT_EQ(qtype, CL_MEM_OBJECT_IMAGE3D);

    clReleaseMemObject(im2d);
    clReleaseMemObject(im3d);
}

TEST_F(WithCommandQueue, DISABLED_TALVOS(BasicImageMapUnmap)) {
    const size_t IMAGE_WIDTH = 97;
    const size_t IMAGE_HEIGHT = 13;

    // Create an image
    cl_image_format format = {CL_RGBA, CL_FLOAT};
    cl_image_desc desc = {
        CL_MEM_OBJECT_IMAGE2D, // image_type
        IMAGE_WIDTH,           // image_width
        IMAGE_HEIGHT,          // image_height
        1,                     // image_depth
        1,                     // image_array_size
        0,                     // image_row_pitch
        0,                     // image_slice_pitch
        0,                     // num_mip_levels
        0,                     // num_samples
        nullptr,               // buffer
    };
    auto image = CreateImage(CL_MEM_READ_WRITE, &format, &desc, nullptr);

    // Map it
    size_t origin[3] = {0, 0, 0};
    size_t region[3] = {IMAGE_WIDTH, IMAGE_HEIGHT, 1};
    size_t row_pitch;
    auto data = EnqueueMapImage<cl_float4>(image, CL_BLOCKING,
                                           CL_MAP_WRITE_INVALIDATE_REGION,
                                           origin, region, &row_pitch, nullptr);
    size_t row_pitch_pixels = row_pitch / sizeof(cl_float4);
    // Fill with pattern
    for (auto row = 0u; row < IMAGE_HEIGHT; row++) {
        for (auto pix = 0u; pix < IMAGE_WIDTH; pix++) {
            data[row * row_pitch_pixels + pix] = {1.0f, 2.0f, 3.0f, 4.0f};
        }
    }

    // Unmap
    EnqueueUnmapMemObject(image, data);
    Finish();

    // Create a sampler
    auto sampler = CreateSampler(CL_FALSE, CL_ADDRESS_CLAMP, CL_FILTER_NEAREST);

    // Create a buffer
    auto buffer_size = IMAGE_HEIGHT * IMAGE_WIDTH * sizeof(cl_float4);
    auto buffer = CreateBuffer(CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR,
                               buffer_size, nullptr);

    // Enqueue kernel to copy to a buffer
    static const char* source = R"(
    kernel void copy(image2d_t read_only img, sampler_t sampler, uint row_pitch, global float4 *buffer)
{
    uint x = get_global_id(0);
    uint y = get_global_id(1);
    int2 coord = {(int)x, (int)y};
    float4 color = read_imagef(img, sampler, coord);
    buffer[(y * row_pitch) + x] = color;
}
)";

    auto kernel = CreateKernel(source, "copy");
    SetKernelArg(kernel, 0, image);
    SetKernelArg(kernel, 1, sampler);
    cl_uint row_pitch_pixels_buffer = IMAGE_WIDTH;
    SetKernelArg(kernel, 2, sizeof(cl_uint), &row_pitch_pixels_buffer);
    SetKernelArg(kernel, 3, buffer);

    size_t gws[3] = {IMAGE_WIDTH, IMAGE_HEIGHT, 0};
    size_t lws[3] = {1, 1, 1};

    EnqueueNDRangeKernel(kernel, 2, nullptr, gws, lws);

    // Map the buffer
    auto bdata = EnqueueMapBuffer<cl_float4>(buffer, CL_TRUE, CL_MAP_READ, 0,
                                             buffer_size);

    // Verify the content
    bool success = true;
    for (cl_uint i = 0; i < IMAGE_HEIGHT * IMAGE_WIDTH; ++i) {
        auto val = bdata[i];
        if ((val.x != 1.0f) || (val.y != 2.0f) || (val.z != 3.0f) ||
            (val.w != 4.0f)) {
            printf("Failed comparison at data[%d]: "
                   "expected {1.0,2.0,3.0,4.0} but got {%f,%f,%f,%f}\n",
                   i, val.x, val.y, val.z, val.w);
            success = false;
        }
    }
    EXPECT_TRUE(success);

    // Unmap the buffer
    EnqueueUnmapMemObject(buffer, bdata);
    Finish();
}

TEST_F(WithCommandQueue, ImageReadMappingCantChangeImage) {
    // Create image
    const size_t IMAGE_WIDTH = 97;
    const size_t IMAGE_HEIGHT = 13;

    cl_image_format format = {CL_R, CL_UNSIGNED_INT8};
    cl_image_desc desc = {
        CL_MEM_OBJECT_IMAGE2D, // image_type
        IMAGE_WIDTH,           // image_width
        IMAGE_HEIGHT,          // image_height
        1,                     // image_depth
        1,                     // image_array_size
        0,                     // image_row_pitch
        0,                     // image_slice_pitch
        0,                     // num_mip_levels
        0,                     // num_samples
        nullptr,               // buffer
    };
    auto image = CreateImage(CL_MEM_READ_WRITE, &format, &desc, nullptr);

    // Init with pattern
    size_t origin[3] = {0, 0, 0};
    size_t region[3] = {IMAGE_WIDTH, IMAGE_HEIGHT, 1};
    const cl_uchar fill_value = 0xAB;
    size_t row_pitch;
    auto data = EnqueueMapImage<cl_uchar>(image, CL_BLOCKING,
                                          CL_MAP_WRITE_INVALIDATE_REGION,
                                          origin, region, &row_pitch, nullptr);
    size_t row_pitch_pixels = row_pitch / sizeof(int8_t);

    for (auto row = 0u; row < IMAGE_HEIGHT; row++) {
        for (auto pix = 0u; pix < IMAGE_WIDTH; pix++) {
            data[row * row_pitch_pixels + pix] = fill_value;
        }
    }

    EnqueueUnmapMemObject(image, data);
    Finish();

    // Map for reading a region
    data = EnqueueMapImage<cl_uchar>(image, CL_BLOCKING, CL_MAP_READ, origin,
                                     region, &row_pitch, nullptr);
    // Change pattern
    for (auto row = 0u; row < IMAGE_HEIGHT; row++) {
        for (auto pix = 0u; pix < IMAGE_WIDTH; pix++) {
            data[row * row_pitch_pixels + pix] = fill_value + pix;
        }
    }

    // Unmap
    EnqueueUnmapMemObject(image, data);
    Finish();

    // Map again
    data = EnqueueMapImage<cl_uchar>(image, CL_BLOCKING, CL_MAP_READ, origin,
                                     region, &row_pitch, nullptr);

    // Check the new pattern isn't in the image
    bool success = true;
    for (cl_uint i = 0; i < IMAGE_HEIGHT * IMAGE_WIDTH; ++i) {
        auto val = data[i];
        if (val != fill_value) {
            success = false;
        }
    }
    EXPECT_TRUE(success);

    EnqueueUnmapMemObject(image, data);
    Finish();
}

TEST_F(WithCommandQueue,
       DISABLED_TALVOS(ImageWriteInvalidateMappingDoesntCopyImageContent)) {
    // Create an image
    const size_t IMAGE_WIDTH = 97;
    const size_t IMAGE_HEIGHT = 13;

    cl_image_format format = {CL_R, CL_UNSIGNED_INT8};
    cl_image_desc desc = {
        CL_MEM_OBJECT_IMAGE2D, // image_type
        IMAGE_WIDTH,           // image_width
        IMAGE_HEIGHT,          // image_height
        1,                     // image_depth
        1,                     // image_array_size
        0,                     // image_row_pitch
        0,                     // image_slice_pitch
        0,                     // num_mip_levels
        0,                     // num_samples
        nullptr,               // buffer
    };
    auto image = CreateImage(CL_MEM_READ_WRITE, &format, &desc, nullptr);

    // Init content
    size_t origin[3] = {0, 0, 0};
    size_t region[3] = {IMAGE_WIDTH, IMAGE_HEIGHT, 1};
    const cl_uchar fill_value = 0x42;
    size_t row_pitch;
    auto data = EnqueueMapImage<cl_uchar>(image, CL_BLOCKING,
                                          CL_MAP_WRITE_INVALIDATE_REGION,
                                          origin, region, &row_pitch, nullptr);
    size_t row_pitch_pixels = row_pitch / sizeof(int8_t);

    for (auto row = 0u; row < IMAGE_HEIGHT; row++) {
        for (auto pix = 0u; pix < IMAGE_WIDTH; pix++) {
            data[row * row_pitch_pixels + pix] = fill_value;
        }
    }

    EnqueueUnmapMemObject(image, data);
    Finish();

    // Map with CL_MAP_WRITE_INVALIDATE_REGION
    data = EnqueueMapImage<cl_uchar>(image, CL_BLOCKING,
                                     CL_MAP_WRITE_INVALIDATE_REGION, origin,
                                     region, &row_pitch, nullptr);

    // Check the pattern isn't visible
    bool success = false;
    for (cl_uint i = 0; i < IMAGE_HEIGHT * IMAGE_WIDTH; ++i) {
        auto val = data[i];
        if (val != fill_value) {
            success = true;
        }
    }
    EXPECT_TRUE(success);

    EnqueueUnmapMemObject(image, data);
    Finish();
}
<commit_msg>Make ImageWriteInvalidateMappingDoesntCopyImageContent test more robust<commit_after>// Copyright 2019 The clvk authors.
//
// 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.

#define CL_USE_DEPRECATED_OPENCL_1_1_APIS

#include "testcl.hpp"

TEST_F(WithContext, CreateImageLegacy) {
    cl_image_format format = {CL_RGBA, CL_UNORM_INT8};

    size_t width = 97, height = 135, depth = 7;
    size_t row_pitch = 128, slice_pitch = row_pitch * height;

    cl_int err;

    // Create 2D image
    auto im2d = clCreateImage2D(m_context, CL_MEM_READ_WRITE, &format, width,
                                height, row_pitch, nullptr, &err);
    ASSERT_CL_SUCCESS(err);

    size_t qval;
    cl_image_format qfmt;

    // Query its properties
    GetImageInfo(im2d, CL_IMAGE_WIDTH, sizeof(qval), &qval, nullptr);
    EXPECT_EQ(qval, width);
    GetImageInfo(im2d, CL_IMAGE_HEIGHT, sizeof(qval), &qval, nullptr);
    EXPECT_EQ(qval, height);
    GetImageInfo(im2d, CL_IMAGE_ROW_PITCH, sizeof(qval), &qval, nullptr);
    EXPECT_EQ(qval, row_pitch);
    GetImageInfo(im2d, CL_IMAGE_FORMAT, sizeof(qfmt), &qfmt, nullptr);
    EXPECT_EQ(qfmt.image_channel_order, format.image_channel_order);
    EXPECT_EQ(qfmt.image_channel_data_type, format.image_channel_data_type);

    cl_mem_object_type qtype;
    GetMemObjectInfo(im2d, CL_MEM_TYPE, sizeof(qtype), &qtype, nullptr);
    EXPECT_EQ(qtype, CL_MEM_OBJECT_IMAGE2D);

    // Do the same for 3D images
    auto im3d =
        clCreateImage3D(m_context, CL_MEM_READ_WRITE, &format, width, height,
                        depth, row_pitch, slice_pitch, nullptr, &err);
    ASSERT_CL_SUCCESS(err);
    GetImageInfo(im3d, CL_IMAGE_WIDTH, sizeof(qval), &qval, nullptr);
    EXPECT_EQ(qval, width);
    GetImageInfo(im3d, CL_IMAGE_HEIGHT, sizeof(qval), &qval, nullptr);
    EXPECT_EQ(qval, height);
    GetImageInfo(im3d, CL_IMAGE_DEPTH, sizeof(qval), &qval, nullptr);
    EXPECT_EQ(qval, depth);
    GetImageInfo(im3d, CL_IMAGE_ROW_PITCH, sizeof(qval), &qval, nullptr);
    EXPECT_EQ(qval, row_pitch);
    GetImageInfo(im3d, CL_IMAGE_SLICE_PITCH, sizeof(qval), &qval, nullptr);
    EXPECT_EQ(qval, slice_pitch);
    GetImageInfo(im3d, CL_IMAGE_FORMAT, sizeof(qfmt), &qfmt, nullptr);
    EXPECT_EQ(qfmt.image_channel_order, format.image_channel_order);
    EXPECT_EQ(qfmt.image_channel_data_type, format.image_channel_data_type);

    GetMemObjectInfo(im3d, CL_MEM_TYPE, sizeof(qtype), &qtype, nullptr);
    EXPECT_EQ(qtype, CL_MEM_OBJECT_IMAGE3D);

    clReleaseMemObject(im2d);
    clReleaseMemObject(im3d);
}

TEST_F(WithCommandQueue, DISABLED_TALVOS(BasicImageMapUnmap)) {
    const size_t IMAGE_WIDTH = 97;
    const size_t IMAGE_HEIGHT = 13;

    // Create an image
    cl_image_format format = {CL_RGBA, CL_FLOAT};
    cl_image_desc desc = {
        CL_MEM_OBJECT_IMAGE2D, // image_type
        IMAGE_WIDTH,           // image_width
        IMAGE_HEIGHT,          // image_height
        1,                     // image_depth
        1,                     // image_array_size
        0,                     // image_row_pitch
        0,                     // image_slice_pitch
        0,                     // num_mip_levels
        0,                     // num_samples
        nullptr,               // buffer
    };
    auto image = CreateImage(CL_MEM_READ_WRITE, &format, &desc, nullptr);

    // Map it
    size_t origin[3] = {0, 0, 0};
    size_t region[3] = {IMAGE_WIDTH, IMAGE_HEIGHT, 1};
    size_t row_pitch;
    auto data = EnqueueMapImage<cl_float4>(image, CL_BLOCKING,
                                           CL_MAP_WRITE_INVALIDATE_REGION,
                                           origin, region, &row_pitch, nullptr);
    size_t row_pitch_pixels = row_pitch / sizeof(cl_float4);
    // Fill with pattern
    for (auto row = 0u; row < IMAGE_HEIGHT; row++) {
        for (auto pix = 0u; pix < IMAGE_WIDTH; pix++) {
            data[row * row_pitch_pixels + pix] = {1.0f, 2.0f, 3.0f, 4.0f};
        }
    }

    // Unmap
    EnqueueUnmapMemObject(image, data);
    Finish();

    // Create a sampler
    auto sampler = CreateSampler(CL_FALSE, CL_ADDRESS_CLAMP, CL_FILTER_NEAREST);

    // Create a buffer
    auto buffer_size = IMAGE_HEIGHT * IMAGE_WIDTH * sizeof(cl_float4);
    auto buffer = CreateBuffer(CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR,
                               buffer_size, nullptr);

    // Enqueue kernel to copy to a buffer
    static const char* source = R"(
    kernel void copy(image2d_t read_only img, sampler_t sampler, uint row_pitch, global float4 *buffer)
{
    uint x = get_global_id(0);
    uint y = get_global_id(1);
    int2 coord = {(int)x, (int)y};
    float4 color = read_imagef(img, sampler, coord);
    buffer[(y * row_pitch) + x] = color;
}
)";

    auto kernel = CreateKernel(source, "copy");
    SetKernelArg(kernel, 0, image);
    SetKernelArg(kernel, 1, sampler);
    cl_uint row_pitch_pixels_buffer = IMAGE_WIDTH;
    SetKernelArg(kernel, 2, sizeof(cl_uint), &row_pitch_pixels_buffer);
    SetKernelArg(kernel, 3, buffer);

    size_t gws[3] = {IMAGE_WIDTH, IMAGE_HEIGHT, 0};
    size_t lws[3] = {1, 1, 1};

    EnqueueNDRangeKernel(kernel, 2, nullptr, gws, lws);

    // Map the buffer
    auto bdata = EnqueueMapBuffer<cl_float4>(buffer, CL_TRUE, CL_MAP_READ, 0,
                                             buffer_size);

    // Verify the content
    bool success = true;
    for (cl_uint i = 0; i < IMAGE_HEIGHT * IMAGE_WIDTH; ++i) {
        auto val = bdata[i];
        if ((val.x != 1.0f) || (val.y != 2.0f) || (val.z != 3.0f) ||
            (val.w != 4.0f)) {
            printf("Failed comparison at data[%d]: "
                   "expected {1.0,2.0,3.0,4.0} but got {%f,%f,%f,%f}\n",
                   i, val.x, val.y, val.z, val.w);
            success = false;
        }
    }
    EXPECT_TRUE(success);

    // Unmap the buffer
    EnqueueUnmapMemObject(buffer, bdata);
    Finish();
}

TEST_F(WithCommandQueue, ImageReadMappingCantChangeImage) {
    // Create image
    const size_t IMAGE_WIDTH = 97;
    const size_t IMAGE_HEIGHT = 13;

    cl_image_format format = {CL_R, CL_UNSIGNED_INT8};
    cl_image_desc desc = {
        CL_MEM_OBJECT_IMAGE2D, // image_type
        IMAGE_WIDTH,           // image_width
        IMAGE_HEIGHT,          // image_height
        1,                     // image_depth
        1,                     // image_array_size
        0,                     // image_row_pitch
        0,                     // image_slice_pitch
        0,                     // num_mip_levels
        0,                     // num_samples
        nullptr,               // buffer
    };
    auto image = CreateImage(CL_MEM_READ_WRITE, &format, &desc, nullptr);

    // Init with pattern
    size_t origin[3] = {0, 0, 0};
    size_t region[3] = {IMAGE_WIDTH, IMAGE_HEIGHT, 1};
    const cl_uchar fill_value = 0xAB;
    size_t row_pitch;
    auto data = EnqueueMapImage<cl_uchar>(image, CL_BLOCKING,
                                          CL_MAP_WRITE_INVALIDATE_REGION,
                                          origin, region, &row_pitch, nullptr);
    size_t row_pitch_pixels = row_pitch / sizeof(int8_t);

    for (auto row = 0u; row < IMAGE_HEIGHT; row++) {
        for (auto pix = 0u; pix < IMAGE_WIDTH; pix++) {
            data[row * row_pitch_pixels + pix] = fill_value;
        }
    }

    EnqueueUnmapMemObject(image, data);
    Finish();

    // Map for reading a region
    data = EnqueueMapImage<cl_uchar>(image, CL_BLOCKING, CL_MAP_READ, origin,
                                     region, &row_pitch, nullptr);
    // Change pattern
    for (auto row = 0u; row < IMAGE_HEIGHT; row++) {
        for (auto pix = 0u; pix < IMAGE_WIDTH; pix++) {
            data[row * row_pitch_pixels + pix] = fill_value + pix;
        }
    }

    // Unmap
    EnqueueUnmapMemObject(image, data);
    Finish();

    // Map again
    data = EnqueueMapImage<cl_uchar>(image, CL_BLOCKING, CL_MAP_READ, origin,
                                     region, &row_pitch, nullptr);

    // Check the new pattern isn't in the image
    bool success = true;
    for (cl_uint i = 0; i < IMAGE_HEIGHT * IMAGE_WIDTH; ++i) {
        auto val = data[i];
        if (val != fill_value) {
            success = false;
        }
    }
    EXPECT_TRUE(success);

    EnqueueUnmapMemObject(image, data);
    Finish();
}

TEST_F(WithCommandQueue,
       DISABLED_TALVOS(ImageWriteInvalidateMappingDoesntCopyImageContent)) {
    // Create an image
    const size_t IMAGE_WIDTH = 97;
    const size_t IMAGE_HEIGHT = 13;

    cl_image_format format = {CL_R, CL_UNSIGNED_INT8};
    cl_image_desc desc = {
        CL_MEM_OBJECT_IMAGE2D, // image_type
        IMAGE_WIDTH,           // image_width
        IMAGE_HEIGHT,          // image_height
        1,                     // image_depth
        1,                     // image_array_size
        0,                     // image_row_pitch
        0,                     // image_slice_pitch
        0,                     // num_mip_levels
        0,                     // num_samples
        nullptr,               // buffer
    };
    auto image = CreateImage(CL_MEM_READ_WRITE, &format, &desc, nullptr);

    // Init content
    size_t origin[3] = {0, 0, 0};
    size_t region[3] = {IMAGE_WIDTH, IMAGE_HEIGHT, 1};
    const cl_uchar fill_value = 0x42;
    size_t row_pitch;
    auto data = EnqueueMapImage<cl_uchar>(image, CL_BLOCKING,
                                          CL_MAP_WRITE_INVALIDATE_REGION,
                                          origin, region, &row_pitch, nullptr);
    size_t row_pitch_pixels = row_pitch / sizeof(int8_t);

    for (auto row = 0u; row < IMAGE_HEIGHT; row++) {
        for (auto pix = 0u; pix < IMAGE_WIDTH; pix++) {
            data[row * row_pitch_pixels + pix] = fill_value;
        }
    }

    EnqueueUnmapMemObject(image, data);
    Finish();

    // Create a buffer of the size of the image to make it less likely that the
    // mapping buffer of the next image map command gets the same region of
    // memory occupied by the mapping buffer of the previous image map.
    auto buffer =
        CreateBuffer(CL_MEM_READ_WRITE, IMAGE_HEIGHT * IMAGE_WIDTH, nullptr);

    // Map with CL_MAP_WRITE_INVALIDATE_REGION
    data = EnqueueMapImage<cl_uchar>(image, CL_BLOCKING,
                                     CL_MAP_WRITE_INVALIDATE_REGION, origin,
                                     region, &row_pitch, nullptr);

    // Check the pattern isn't visible
    bool success = false;
    for (cl_uint i = 0; i < IMAGE_HEIGHT * IMAGE_WIDTH; ++i) {
        auto val = data[i];
        if (val != fill_value) {
            success = true;
        }
    }
    EXPECT_TRUE(success);

    EnqueueUnmapMemObject(image, data);
    Finish();
}
<|endoftext|>


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

#include "rdtsc.h"

#include "cache.h"

/** Benchmark runner class.
  * Base class for all tests.
  * @param Derived derived class
  * @param NIter number of iterations
  */
template<class Derived, int NIter>
class BenchmarkRunner {
    std::array<unsigned long long, NIter> results_;
    unsigned long long median_, min_, max_;
protected:
    std::string name_;
public:

    void execute() {
        CPUCounter cnt;
        for (int i = 0; i < NIter; i++) {
            cnt.reset();
            static_cast<Derived*>(this)->run();
            auto res = cnt.elapsed();
            results_[i] = res;
        }

        // process results
        std::sort(results_.begin(), results_.end());
        median_ = results_[NIter / 2];
        min_ = results_[0];
        max_ = results_[NIter - 1];

        std::cout << name_ << " min=" << min_ << " median=" << median_ << " max=" << max_ << std::endl;
    }
};

using namespace Akumuli;

struct GenFindTest : BenchmarkRunner<GenFindTest, 1000> {
    Generation gen_;

    GenFindTest()
        : gen_(TimeDuration::make(1000L), 10000000u)
    {
        name_ = "Generation(find)";

        for (int i = 0; i < 100; i++) {
            gen_.add(TimeStamp::make(i*10L), i % 5, i);
        }
    }

    void run() {
        EntryOffset off[10];
        gen_.find(TimeStamp::make(500L), 0, off, 10, 0);
        gen_.find(TimeStamp::make(100L), 0, off, 10, 0);
        gen_.find(TimeStamp::make(900L), 0, off, 10, 0);
    }
};

int main() {
    GenFindTest gen_find_test;
    gen_find_test.execute();
    return 0;
}
<commit_msg>Perf-test suite improved.<commit_after>#include <iostream>
#include <vector>
#include <algorithm>

#include "rdtsc.h"

#include "cache.h"

/** Benchmark runner class.
  * Base class for all tests.
  * @param Derived derived class
  * @param NIter number of iterations
  */
template<class Derived, int NIter>
class BenchmarkRunner {
    std::vector<unsigned long long> results_;
    unsigned long long median_, min_;
protected:
    std::string name_;
public:

    BenchmarkRunner()
        : results_(NIter, 0)
    {}

    void execute() {
        CPUCounter cnt;
        for (int i = 0; i < NIter; i++) {
            cnt.reset();
            static_cast<Derived*>(this)->run();
            auto res = cnt.elapsed();
            results_[i] = res;
        }

        // process results
        std::sort(results_.begin(), results_.end());
        median_ = results_[NIter / 2];
        min_ = results_[0];

        std::cout << name_ << " min=" << min_ << " median=" << median_ << std::endl;
    }
};

using namespace Akumuli;

struct GenFindTest : BenchmarkRunner<GenFindTest, 100000> {
    Generation gen_;

    GenFindTest()
        : gen_(TimeDuration::make(1000L), 10000000u)
    {
        name_ = "Generation(find)";

        for (int i = 0; i < 100; i++) {
            gen_.add(TimeStamp::make(10L), 5, i);
        }
    }

    void run() {
        EntryOffset off[50];
        gen_.find(TimeStamp::make(10L), 5, off, 10, 50);
    }
};

int main() {
    GenFindTest gen_find_test;
    gen_find_test.execute();
    return 0;
}
<|endoftext|>


<commit_before>#include "math/numeric.h"
#include "layer_normalize.h"

using namespace nano;

template <typename tidata, typename todata>
static void onorm(const tidata& idata, todata&& odata)
{
        const auto isum1 = idata.array().sum();
        const auto isum2 = idata.array().square().sum();
        const auto count = static_cast<scalar_t>(idata.size());
        const auto imean = isum1 / count;
        const auto istdv = std::sqrt((isum2 - isum1 * isum1 / count) / count);

        odata.array() = (idata.array() - imean) / istdv;
}

template <typename tidata, typename todata>
static void gnorm(tidata&& idata, const todata& odata)
{
        const auto isum1 = idata.array().sum();
        const auto isum2 = idata.array().square().sum();
        const auto count = static_cast<scalar_t>(idata.size());
        const auto imean = isum1 / count;
        const auto istdv = std::sqrt((isum2 - isum1 * isum1 / count) / count);

        const auto osum1 = odata.array().sum();
        const auto oisum = (odata.array() * (idata.array() - imean)).sum();

        idata.array() =
                odata.array() / (istdv) -
                osum1 / (count * istdv) -
                (idata.array() - imean) * oisum / (count * istdv * istdv * istdv);
}

normalize_layer_t::normalize_layer_t(const string_t& params) :
        layer_t(to_params(params, "type", norm_type::plane)),
        m_idims({0, 0, 0}),
        m_odims({0, 0, 0}),
        m_type(norm_type::plane)
{
}

void normalize_layer_t::configure(const tensor3d_dims_t& idims, const string_t& name)
{
        m_idims = idims;
        m_odims = idims;
        m_type = from_params<norm_type>(config(), "type");

        m_probe_output = probe_t{name, name + "(output)", 10 * isize()};
        m_probe_ginput = probe_t{name, name + "(ginput)", 10 * isize()};
        m_probe_gparam = probe_t{name, name + "(gparam)", 0};
}

void normalize_layer_t::output(tensor3d_const_map_t idata, tensor1d_const_map_t param, tensor3d_map_t odata)
{
        assert(idata.dims() == idims());
        assert(param.size() == psize());
        assert(odata.dims() == odims());
        NANO_UNUSED1_RELEASE(param);

        m_probe_output.measure([&] ()
        {
                switch (m_type)
                {
                case norm_type::global:
                        onorm(idata, odata);
                        break;
                case norm_type::plane:
                        for (tensor_size_t i = 0; i < std::get<0>(m_idims); ++ i)
                        {
                                onorm(idata.array(i), odata.array(i));
                        }
                        break;
                }
        });
}

void normalize_layer_t::ginput(tensor3d_map_t idata, tensor1d_const_map_t param, tensor3d_const_map_t odata)
{
        assert(idata.dims() == idims());
        assert(param.size() == psize());
        assert(odata.dims() == odims());
        NANO_UNUSED1_RELEASE(param);

        m_probe_ginput.measure([&] ()
        {
                switch (m_type)
                {
                case norm_type::global:
                        gnorm(idata, odata);
                        break;
                case norm_type::plane:
                        for (tensor_size_t i = 0; i < std::get<0>(m_idims); ++ i)
                        {
                                gnorm(idata.array(i), odata.array(i));
                        }
                        break;
                }
        });
}

void normalize_layer_t::gparam(tensor3d_const_map_t idata, tensor1d_map_t param, tensor3d_const_map_t odata)
{
        assert(idata.dims() == idims());
        assert(param.size() == psize());
        assert(odata.dims() == odims());
        NANO_UNUSED3_RELEASE(idata, param, odata);
}

rlayer_t normalize_layer_t::clone() const
{
        return std::make_unique<normalize_layer_t>(*this);
}
<commit_msg>better estimate the number of flops for the normalization layer<commit_after>#include "math/numeric.h"
#include "layer_normalize.h"

using namespace nano;

template <typename tidata, typename todata>
static void onorm(const tidata& idata, todata&& odata)
{
        const auto isum1 = idata.array().sum();
        const auto isum2 = idata.array().square().sum();
        const auto count = static_cast<scalar_t>(idata.size());
        const auto imean = isum1 / count;
        const auto istdv = std::sqrt((isum2 - isum1 * isum1 / count) / count);

        odata.array() = (idata.array() - imean) / istdv;
}

template <typename tidata, typename todata>
static void gnorm(tidata&& idata, const todata& odata)
{
        const auto isum1 = idata.array().sum();
        const auto isum2 = idata.array().square().sum();
        const auto count = static_cast<scalar_t>(idata.size());
        const auto imean = isum1 / count;
        const auto istdv = std::sqrt((isum2 - isum1 * isum1 / count) / count);

        const auto osum1 = odata.array().sum();
        const auto oisum = (odata.array() * (idata.array() - imean)).sum();

        idata.array() =
                odata.array() / (istdv) -
                osum1 / (count * istdv) -
                (idata.array() - imean) * oisum / (count * istdv * istdv * istdv);
}

normalize_layer_t::normalize_layer_t(const string_t& params) :
        layer_t(to_params(params, "type", norm_type::plane)),
        m_idims({0, 0, 0}),
        m_odims({0, 0, 0}),
        m_type(norm_type::plane)
{
}

void normalize_layer_t::configure(const tensor3d_dims_t& idims, const string_t& name)
{
        m_idims = idims;
        m_odims = idims;
        m_type = from_params<norm_type>(config(), "type");

        m_probe_output = probe_t{name, name + "(output)", 5 * isize()};
        m_probe_ginput = probe_t{name, name + "(ginput)", 12 * isize()};
        m_probe_gparam = probe_t{name, name + "(gparam)", 0};
}

void normalize_layer_t::output(tensor3d_const_map_t idata, tensor1d_const_map_t param, tensor3d_map_t odata)
{
        assert(idata.dims() == idims());
        assert(param.size() == psize());
        assert(odata.dims() == odims());
        NANO_UNUSED1_RELEASE(param);

        m_probe_output.measure([&] ()
        {
                switch (m_type)
                {
                case norm_type::global:
                        onorm(idata, odata);
                        break;
                case norm_type::plane:
                        for (tensor_size_t i = 0; i < std::get<0>(m_idims); ++ i)
                        {
                                onorm(idata.array(i), odata.array(i));
                        }
                        break;
                }
        });
}

void normalize_layer_t::ginput(tensor3d_map_t idata, tensor1d_const_map_t param, tensor3d_const_map_t odata)
{
        assert(idata.dims() == idims());
        assert(param.size() == psize());
        assert(odata.dims() == odims());
        NANO_UNUSED1_RELEASE(param);

        m_probe_ginput.measure([&] ()
        {
                switch (m_type)
                {
                case norm_type::global:
                        gnorm(idata, odata);
                        break;
                case norm_type::plane:
                        for (tensor_size_t i = 0; i < std::get<0>(m_idims); ++ i)
                        {
                                gnorm(idata.array(i), odata.array(i));
                        }
                        break;
                }
        });
}

void normalize_layer_t::gparam(tensor3d_const_map_t idata, tensor1d_map_t param, tensor3d_const_map_t odata)
{
        assert(idata.dims() == idims());
        assert(param.size() == psize());
        assert(odata.dims() == odims());
        NANO_UNUSED3_RELEASE(idata, param, odata);
}

rlayer_t normalize_layer_t::clone() const
{
        return std::make_unique<normalize_layer_t>(*this);
}
<|endoftext|>


<commit_before>#include <node.h>
#include <node_buffer.h>
#include <string.h>
#include <v8.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
#ifdef __APPLE__
#include <malloc/malloc.h>
#endif
#include <zlib.h>

// zlib magic something
#define WBITS 16+MAX_WBITS
#define WBITS_RAW -15

#define CHUNK 1024*100
#define HEADER_SIZE 10
#define FOOTER_SIZE 8
#define SPACER_SIZE 6

using namespace v8;
using namespace node;

static Persistent<String> SYM_BODY;
static Persistent<String> SYM_LEFT;
static Persistent<String> SYM_RIGHT;
static Persistent<String> SYM_LAST;
static Persistent<String> SYM_TYPE;
static Persistent<String> SYM_OFFSETS;
static Persistent<String> SYM_LENGTH;
static Persistent<String> SYM_RAW_LENGTH;
static Persistent<String> SYM_CRC;
static Persistent<String> SYM_META;
static Persistent<String> SYM_BUFFERS;
static Persistent<String> SYM_HEADER;
static Persistent<String> SYM_ODD;
unsigned char *tmpBody;

static Handle<Value> ThrowNodeError (const char* what = NULL) {
    return ThrowException(Exception::Error(String::New(what)));
}

static int meta_uncompress (char *dataIn, size_t bytesIn, int *dataType) {
    unsigned char *bodyDataIn = ((unsigned char *) dataIn) + HEADER_SIZE;

    //checking if stream is compressed, first byte - binary:
    //xxxxx001 - stream is NOT compressed
    //xxxxx011 - stream is compressed (using fixed huffman codes)
    //xxxxx111 - stream is compressed (using dynamic huffman codes)
    if ((*bodyDataIn & 3) == 3 || (*bodyDataIn & 5) == 5) {
        z_stream strmUncompress;

        strmUncompress.zalloc = Z_NULL;
        strmUncompress.zfree = Z_NULL;
        strmUncompress.opaque = Z_NULL;
        strmUncompress.avail_in = 0;
        strmUncompress.next_in = Z_NULL;

        if (inflateInit2(&strmUncompress, WBITS_RAW) != Z_OK) {
            return -1;
        }

        //skipping header
        strmUncompress.next_in = bodyDataIn;
        strmUncompress.avail_in = bytesIn - HEADER_SIZE;

        for (;;) {
            strmUncompress.avail_out = CHUNK;
            strmUncompress.next_out = tmpBody;

            int ret = inflate(&strmUncompress, Z_BLOCK);

            assert(ret != Z_STREAM_ERROR);

            switch (ret) {
                case Z_NEED_DICT:
                    ret = Z_DATA_ERROR;     /* and fall through */
                case Z_DATA_ERROR:
                case Z_MEM_ERROR:
                    inflateEnd(&strmUncompress);
                    return -2;
            }

            if (strmUncompress.data_type & 128) {
                break;
            }
        }
        *dataType = strmUncompress.data_type;

        inflateEnd(&strmUncompress);
    } else {
        *dataType = 128;
    }

    return 0;

}

static int compress (char *dataIn, size_t bytesIn, int compressionLevel, char **dataOut, size_t *bytesOut) {
    size_t bytesDeflated = 0;

    if (compressionLevel < 0 || compressionLevel > 9) {
        compressionLevel = Z_DEFAULT_COMPRESSION;
    }

    z_stream strmCompress;
    strmCompress.zalloc = Z_NULL;
    strmCompress.zfree = Z_NULL;
    strmCompress.opaque = Z_NULL;

    if (deflateInit2(&strmCompress, compressionLevel, Z_DEFLATED, WBITS, 8L, Z_DEFAULT_STRATEGY) != Z_OK) {
        return -1;
    }

    bytesDeflated = deflateBound(&strmCompress, bytesIn);

    if (bytesDeflated < 1024) {
        bytesDeflated = 1024;
    }

    *dataOut = (char *) malloc(bytesDeflated);

    strmCompress.next_in = (Bytef *) dataIn;
    strmCompress.avail_in = bytesIn;
    strmCompress.next_out = (Bytef *) *dataOut;
    strmCompress.avail_out = bytesDeflated;

    if (deflate(&strmCompress, Z_NO_FLUSH) < Z_OK) {
        deflateEnd(&strmCompress);
        return -2;
    }

    deflate(&strmCompress, Z_FINISH);

    *bytesOut = strmCompress.total_out;

    deflateEnd(&strmCompress);

    return 0;
}

static Handle<Value> onet_compress (const Arguments &args) {
    HandleScope scope;

    int compressionLevel = Z_DEFAULT_COMPRESSION;

    if (args.Length() < 1) {
        return Undefined();
    }

    if (!Buffer::HasInstance(args[0])) {
        ThrowNodeError("First argument must be a Buffer");
        return Undefined();
    }

    Local<Object> bufferIn = args[0]->ToObject();

    if (args.Length() > 1) {
        compressionLevel = args[1]->IntegerValue();
    }

    char *dataIn = Buffer::Data(bufferIn);
    size_t bytesIn = Buffer::Length(bufferIn);
    char *dataOut = 0;
    size_t bytesOut = 0;
    int dataType = 0;
    int status = compress(dataIn, bytesIn, compressionLevel, &dataOut, &bytesOut);

    if (status != 0) {
        if (dataOut) {
            free(dataOut);
        }

        char msg[30];
        sprintf(msg, "Unable to compress: %d", status);
        ThrowNodeError(msg);
        return Undefined();
    }

    status = meta_uncompress(dataOut, bytesOut, &dataType);

    if (status != 0) {
        char msg[30];
        sprintf(msg, "Unable to uncompress: %d", status);
        ThrowNodeError(msg);
        return Undefined();
    }

    unsigned int dataLength = bytesOut - HEADER_SIZE - FOOTER_SIZE - 1;

    Local<Object> result = Object::New();

    Buffer *body = Buffer::New((char *) dataOut, bytesOut);
    result->Set(SYM_BODY, body->handle_);

    Local<Object> dataOffsets = Object::New();
    dataOffsets->Set(SYM_LEFT, Integer::New(HEADER_SIZE));
    dataOffsets->Set(SYM_RIGHT, Integer::New(HEADER_SIZE + dataLength));
    dataOffsets->Set(SYM_LAST, Integer::New(HEADER_SIZE + dataLength));

    Buffer *crc = Buffer::New((char *) dataOut + (bytesOut - FOOTER_SIZE), 4);

    Local<Object> meta = Object::New();
    meta->Set(SYM_TYPE, Integer::New(dataType));
    meta->Set(SYM_OFFSETS, dataOffsets);
    meta->Set(SYM_LENGTH, Integer::New(bytesIn));
    meta->Set(SYM_RAW_LENGTH, Integer::New(bytesOut - HEADER_SIZE - FOOTER_SIZE));
    meta->Set(SYM_CRC, crc->handle_);

    result->Set(SYM_META, meta);

    free(dataOut);

    return scope.Close(result);
}

static Handle<Value> compress (const Arguments& args) {
    HandleScope scope;

    int compressionLevel = Z_DEFAULT_COMPRESSION;

    if (args.Length() < 1) {
        return Undefined();
    }

    if (!Buffer::HasInstance(args[0])) {
        ThrowNodeError("First argument must be a Buffer");
        return Undefined();
    }

    Local<Object> bufferIn = args[0]->ToObject();

    if (args.Length() > 1) {
        compressionLevel = args[1]->IntegerValue();
    }

    char *dataIn = Buffer::Data(bufferIn);
    size_t bytesIn = Buffer::Length(bufferIn);
    char *dataOut = 0;
    size_t bytesOut = 0;
    int status = compress(dataIn, bytesIn, compressionLevel, &dataOut, &bytesOut);

    if (status != 0) {
        if (dataOut) {
            free(dataOut);
        }
        ThrowNodeError("Unable to compress");
        return Undefined();
    }

    Buffer *buff = Buffer::New(dataOut, bytesOut);

    return scope.Close(buff->handle_);
}

static Handle<Value> estimate (const Arguments &args) {
    HandleScope scope;

    Local<Array> arr = Local<Array>::Cast(args[0]);
    int i = 0;
    int l = arr->Length();
    int sum = HEADER_SIZE + FOOTER_SIZE + ((l - 1) * SPACER_SIZE);

    for(; i < l; i++) {
        Local<Object> obj = arr->Get(i)->ToObject();
        Local<Object> meta = obj->Get(SYM_META)->ToObject();

        sum += meta->Get(SYM_RAW_LENGTH)->Uint32Value();
    }

    return scope.Close(Integer::New(sum));
}

static unsigned long reverseBytes (unsigned char *buf) {
    unsigned long v;

    v = *buf;
    v += (unsigned long) *(buf + 1) << 8;
    v += (unsigned long) *(buf + 2) << 16;
    v += (unsigned long) *(buf + 3) << 24;

    return v;
}

static Handle<Value> getCrc (const Arguments &args) {
    HandleScope scope;

    unsigned long crc = crc32(0L, Z_NULL, 0);
    unsigned long tot = 0;

    Local<Array> arr = Local<Array>::Cast(args[0]);

    int l = arr->Length();
    int i = 0;

    for (; i < l; i++) {
        Local<Object> obj = arr->Get(i)->ToObject();
        Local<Object> meta = obj->Get(SYM_META)->ToObject();

        Local<Value> objCrc = meta->Get(SYM_CRC);
        if (!Buffer::HasInstance(objCrc)) {
            char msg[40];
            sprintf(msg, "CRC32 is not a buffer at: %d", i);
            ThrowNodeError(msg);
            return Undefined();
        }

        Local<Object> bufCrc = objCrc->ToObject();

        unsigned long tmpCrc = reverseBytes((unsigned char *) Buffer::Data(bufCrc));
        unsigned long tmpLen = meta->Get(SYM_LENGTH)->Uint32Value();

        crc = crc32_combine(crc, tmpCrc, tmpLen);
        tot += tmpLen;
    }

    Local<Object> data = Object::New();
    data->Set(SYM_CRC, Buffer::New((char *) &crc, 4)->handle_);
    data->Set(SYM_LENGTH, Buffer::New((char *) &tot, 4)->handle_);

    return scope.Close(data);
}

static Handle<Value> uncompress (const Arguments &args) {
    HandleScope scope;

    if (args.Length() < 1) {
        return Undefined();
    }

    if (!Buffer::HasInstance(args[0])) {
        ThrowNodeError("First argument must be a Buffer");
        return Undefined();
    }

    z_stream strmUncompress;

    strmUncompress.zalloc=Z_NULL;
    strmUncompress.zfree=Z_NULL;
    strmUncompress.opaque=Z_NULL;
    strmUncompress.avail_in = 0;
    strmUncompress.next_in = Z_NULL;

    int rci = inflateInit2(&strmUncompress, WBITS);

    if (rci != Z_OK) {
        ThrowNodeError("zlib initialization error.");
        return Undefined();
    }

    Local<Object> bufferIn=args[0]->ToObject();

    strmUncompress.next_in = (Bytef*) Buffer::Data(bufferIn);
    strmUncompress.avail_in = Buffer::Length(bufferIn);

    Bytef  *bufferOut = NULL;
    uint32_t malloc_size=0;
    uint32_t currentPosition=0;

    int ret;

    do {
        Bytef *tmp = (Bytef*)malloc(CHUNK);
        strmUncompress.avail_out = CHUNK;
        strmUncompress.next_out = tmp;

        ret = inflate(&strmUncompress, Z_NO_FLUSH);
        assert(ret != Z_STREAM_ERROR);
        switch (ret) {
            case Z_NEED_DICT:
                ret = Z_DATA_ERROR;     /* and fall through */
            case Z_DATA_ERROR:
            case Z_MEM_ERROR:
                (void)inflateEnd(&strmUncompress);
                if (bufferOut!=NULL) {
                    free(bufferOut);
                }
                if (tmp!=NULL) {
                    free(tmp);
                }
                return Undefined();
        }

        uint32_t have = CHUNK - strmUncompress.avail_out;
        if (have>0) {
            bufferOut = (Bytef *) realloc(bufferOut, malloc_size+have);
            malloc_size=malloc_size+have;
        }

        memcpy(bufferOut+currentPosition, tmp, have);
        currentPosition+=have;
        free(tmp);
    } while (strmUncompress.avail_out == 0 && ret != Z_STREAM_END);

    inflateEnd(&strmUncompress);

    if (ret != Z_STREAM_END) {
        if (bufferOut!=NULL) {
            free(bufferOut);
        }
        return Undefined();
    }

    Buffer *BufferOut=Buffer::New((char *)bufferOut, malloc_size);
    free(bufferOut);

    return scope.Close(BufferOut->handle_);
}

extern "C" void init (Handle<Object> target) {
    SYM_BODY = NODE_PSYMBOL("body");
    SYM_LEFT = NODE_PSYMBOL("left");
    SYM_RIGHT = NODE_PSYMBOL("right");
    SYM_LAST = NODE_PSYMBOL("last");
    SYM_TYPE = NODE_PSYMBOL("type");
    SYM_OFFSETS = NODE_PSYMBOL("offsets");
    SYM_LENGTH = NODE_PSYMBOL("length");
    SYM_RAW_LENGTH = NODE_PSYMBOL("rawLength");
    SYM_CRC = NODE_PSYMBOL("crc");
    SYM_META = NODE_PSYMBOL("meta");
    SYM_BUFFERS = NODE_PSYMBOL("buffers");
    SYM_HEADER = NODE_PSYMBOL("header");
    SYM_ODD = NODE_PSYMBOL("odd");
    tmpBody = (unsigned char *) malloc(CHUNK);

    char header[] = {0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
    Buffer *headerBuffer = Buffer::New(header, 10);

    char odd[] = {0x00, 0x00, 0xff, 0xff};
    Buffer *oddBuffer = Buffer::New(odd, 4);

    Handle<Object> buffers = Object::New();
    buffers->Set(SYM_HEADER, headerBuffer->handle_);
    buffers->Set(SYM_ODD, oddBuffer->handle_);

    target->Set(SYM_BUFFERS, buffers);

    NODE_SET_METHOD(target, "compress", compress);
    NODE_SET_METHOD(target, "uncompress", uncompress);
    NODE_SET_METHOD(target, "metaCompress", onet_compress);
    NODE_SET_METHOD(target, "getCrc", getCrc);
    NODE_SET_METHOD(target, "estimate", estimate);

}

NODE_MODULE(compress_buffer_bindings, init);

<commit_msg>Added boundary calculation, correctly preparing gzip blocks for combining in larger streams.<commit_after>#include <node.h>
#include <node_buffer.h>
#include <string.h>
#include <v8.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
#ifdef __APPLE__
#include <malloc/malloc.h>
#endif
#include <zlib.h>

// zlib magic something
#define WBITS 16+MAX_WBITS
#define WBITS_RAW -15

#define CHUNK 1024*100
#define HEADER_SIZE 10
#define FOOTER_SIZE 8
#define SPACER_SIZE 6

using namespace v8;
using namespace node;

static Persistent<String> SYM_BODY;
static Persistent<String> SYM_BOUNDARY;
static Persistent<String> SYM_LEFT;
static Persistent<String> SYM_RIGHT;
static Persistent<String> SYM_LAST_BLOCK;
static Persistent<String> SYM_TYPE;
static Persistent<String> SYM_OFFSETS;
static Persistent<String> SYM_LENGTH;
static Persistent<String> SYM_RAW_LENGTH;
static Persistent<String> SYM_CRC;
static Persistent<String> SYM_META;
static Persistent<String> SYM_BUFFERS;
static Persistent<String> SYM_HEADER;
static Persistent<String> SYM_ODD;
unsigned char *tmpBody;

static Handle<Value> ThrowNodeError (const char* what = NULL) {
    return ThrowException(Exception::Error(String::New(what)));
}

static int meta_uncompress (char **dataIn, size_t bytesIn, char **dataBoundary, size_t *bytesBoundary, int *lastBlockPosition) {
    int last;
    int pos;

    z_stream strmUncompress;

    strmUncompress.zalloc = Z_NULL;
    strmUncompress.zfree = Z_NULL;
    strmUncompress.opaque = Z_NULL;
    strmUncompress.avail_in = 0;
    strmUncompress.next_in = Z_NULL;

    if (inflateInit2(&strmUncompress, WBITS_RAW) != Z_OK) {
        return -1;
    }

    //skipping header
    unsigned char *bodyDataIn = ((unsigned char *) *dataIn) + HEADER_SIZE;

    strmUncompress.next_in = bodyDataIn;
    strmUncompress.avail_in = bytesIn - HEADER_SIZE;

    //is there only one block in the stream?
    last = bodyDataIn[0] & 1;
    if (last) {
        *(*dataIn + (bytesIn - strmUncompress.avail_in)) &= ~1;
        *lastBlockPosition = bytesIn - strmUncompress.avail_in;
    }

    for (;;) {
        strmUncompress.avail_out = CHUNK;
        strmUncompress.next_out = tmpBody;

        int ret = inflate(&strmUncompress, Z_BLOCK);

        assert(ret != Z_STREAM_ERROR);

        switch (ret) {
            case Z_NEED_DICT:
                ret = Z_DATA_ERROR;     /* and fall through */
            case Z_DATA_ERROR:
            case Z_MEM_ERROR:
                inflateEnd(&strmUncompress);
                return -2;
        }

        if (strmUncompress.data_type & 128) {
            if (last) {
                break;
            }

            pos = strmUncompress.data_type & 7;

            if (pos != 0) {
                pos = 0x100 >> pos;

                last = strmUncompress.next_in[-1] & pos;
                if (last) {
                    *lastBlockPosition = bytesIn - strmUncompress.avail_in - 1;
                    *(*dataIn + *lastBlockPosition) &= ~pos;
                }
            } else {
                last = strmUncompress.next_in[0] & 1;
                if (last) {
                    *lastBlockPosition = bytesIn - strmUncompress.avail_in;
                    *(*dataIn + *lastBlockPosition) &= ~1;
                }
            }
        }
    }

    last = strmUncompress.next_in[-1];
    pos = strmUncompress.data_type & 7;

    if (pos == 0) {
        *(*dataBoundary + *bytesBoundary) = last;
        (*bytesBoundary)++;
    } else {
        last &= ((0x100 >> pos) - 1);

        if (pos & 1) {
            *(*dataBoundary + *bytesBoundary) = last;
            (*bytesBoundary)++;

            if (pos == 1) {
                *(*dataBoundary + *bytesBoundary) = 0x00;
                (*bytesBoundary)++;
            }

            memcpy((*dataBoundary + *bytesBoundary), "\0\0\xff\xff", 4);
            *bytesBoundary += 4;
        } else {
            switch (pos) {
                case 6:
                    *(*dataBoundary + *bytesBoundary) = last | 0x08;
                    (*bytesBoundary)++;
                    last = 0;
                case 4:
                    *(*dataBoundary + *bytesBoundary) = last | 0x20;
                    (*bytesBoundary)++;
                    last = 0;
                case 2:
                    *(*dataBoundary + *bytesBoundary) = last | 0x80;
                    (*bytesBoundary)++;
                    *(*dataBoundary + *bytesBoundary) = 0x00;
                    (*bytesBoundary)++;
            }
        }
    }

    *lastBlockPosition = *lastBlockPosition - HEADER_SIZE;

    inflateEnd(&strmUncompress);

    return 0;
}

static int compress (char *dataIn, size_t bytesIn, int compressionLevel, char **dataOut, size_t *bytesOut) {
    size_t bytesDeflated = 0;

    if (compressionLevel < 0 || compressionLevel > 9) {
        compressionLevel = Z_DEFAULT_COMPRESSION;
    }

    z_stream strmCompress;
    strmCompress.zalloc = Z_NULL;
    strmCompress.zfree = Z_NULL;
    strmCompress.opaque = Z_NULL;

    if (deflateInit2(&strmCompress, compressionLevel, Z_DEFLATED, WBITS, 8L, Z_DEFAULT_STRATEGY) != Z_OK) {
        return -1;
    }

    bytesDeflated = deflateBound(&strmCompress, bytesIn);

    if (bytesDeflated < 1024) {
        bytesDeflated = 1024;
    }

    *dataOut = (char *) malloc(bytesDeflated);

    strmCompress.next_in = (Bytef *) dataIn;
    strmCompress.avail_in = bytesIn;
    strmCompress.next_out = (Bytef *) *dataOut;
    strmCompress.avail_out = bytesDeflated;

    if (deflate(&strmCompress, Z_NO_FLUSH) < Z_OK) {
        deflateEnd(&strmCompress);
        return -2;
    }

    deflate(&strmCompress, Z_FINISH);

    *bytesOut = strmCompress.total_out;

    deflateEnd(&strmCompress);

    return 0;
}

static Handle<Value> onet_compress (const Arguments &args) {
    HandleScope scope;

    int compressionLevel = Z_DEFAULT_COMPRESSION;

    if (args.Length() < 1) {
        return Undefined();
    }

    if (!Buffer::HasInstance(args[0])) {
        ThrowNodeError("First argument must be a Buffer");
        return Undefined();
    }

    Local<Object> bufferIn = args[0]->ToObject();

    if (args.Length() > 1) {
        compressionLevel = args[1]->IntegerValue();
    }

    char *dataIn = Buffer::Data(bufferIn);
    size_t bytesIn = Buffer::Length(bufferIn);
    char *dataOut = 0;
    char *dataBoundary = (char *) malloc(SPACER_SIZE);
    size_t bytesOut = 0;
    size_t bytesBoundary = 0;
    int lastBlockPosition = 0;

    int status = compress(dataIn, bytesIn, compressionLevel, &dataOut, &bytesOut);

    if (status != 0) {
        if (dataOut) {
            free(dataOut);
        }

        char msg[30];
        sprintf(msg, "Unable to compress: %d", status);
        ThrowNodeError(msg);
        return Undefined();
    }

    status = meta_uncompress(&dataOut, bytesOut, &dataBoundary, &bytesBoundary, &lastBlockPosition);

    if (status != 0) {
        char msg[30];
        sprintf(msg, "Unable to uncompress: %d", status);
        ThrowNodeError(msg);
        return Undefined();
    }

    unsigned int dataLength = bytesOut - HEADER_SIZE - FOOTER_SIZE - 1;

    Local<Object> result = Object::New();

    Buffer *body = Buffer::New((char *) dataOut, bytesOut);
    result->Set(SYM_BODY, body->handle_);

    Buffer *boundary = Buffer::New((char *) dataBoundary, bytesBoundary);
    result->Set(SYM_BOUNDARY, boundary->handle_);

    Local<Object> dataOffsets = Object::New();
    dataOffsets->Set(SYM_LEFT, Integer::New(HEADER_SIZE));
    dataOffsets->Set(SYM_RIGHT, Integer::New(HEADER_SIZE + dataLength));
    dataOffsets->Set(SYM_LAST_BLOCK, Integer::New(lastBlockPosition));

    Buffer *crc = Buffer::New((char *) dataOut + (bytesOut - FOOTER_SIZE), 4);

    Local<Object> meta = Object::New();
    meta->Set(SYM_OFFSETS, dataOffsets);
    meta->Set(SYM_LENGTH, Integer::New(bytesIn));
    meta->Set(SYM_RAW_LENGTH, Integer::New(bytesOut - HEADER_SIZE - FOOTER_SIZE));
    meta->Set(SYM_CRC, crc->handle_);

    result->Set(SYM_META, meta);

    free(dataOut);
    free(dataBoundary);

    return scope.Close(result);
}

static Handle<Value> compress (const Arguments& args) {
    HandleScope scope;

    int compressionLevel = Z_DEFAULT_COMPRESSION;

    if (args.Length() < 1) {
        return Undefined();
    }

    if (!Buffer::HasInstance(args[0])) {
        ThrowNodeError("First argument must be a Buffer");
        return Undefined();
    }

    Local<Object> bufferIn = args[0]->ToObject();

    if (args.Length() > 1) {
        compressionLevel = args[1]->IntegerValue();
    }

    char *dataIn = Buffer::Data(bufferIn);
    size_t bytesIn = Buffer::Length(bufferIn);
    char *dataOut = 0;
    size_t bytesOut = 0;
    int status = compress(dataIn, bytesIn, compressionLevel, &dataOut, &bytesOut);

    if (status != 0) {
        if (dataOut) {
            free(dataOut);
        }
        ThrowNodeError("Unable to compress");
        return Undefined();
    }

    Buffer *buff = Buffer::New(dataOut, bytesOut);

    return scope.Close(buff->handle_);
}

static Handle<Value> estimate (const Arguments &args) {
    HandleScope scope;

    Local<Array> arr = Local<Array>::Cast(args[0]);
    int i = 0;
    int l = arr->Length();
    int sum = HEADER_SIZE + FOOTER_SIZE + ((l - 1) * SPACER_SIZE);

    for(; i < l; i++) {
        Local<Object> obj = arr->Get(i)->ToObject();
        Local<Object> meta = obj->Get(SYM_META)->ToObject();

        sum += meta->Get(SYM_RAW_LENGTH)->Uint32Value();
    }

    return scope.Close(Integer::New(sum));
}

static unsigned long reverseBytes (unsigned char *buf) {
    unsigned long v;

    v = *buf;
    v += (unsigned long) *(buf + 1) << 8;
    v += (unsigned long) *(buf + 2) << 16;
    v += (unsigned long) *(buf + 3) << 24;

    return v;
}

static Handle<Value> getCrc (const Arguments &args) {
    HandleScope scope;

    unsigned long crc = crc32(0L, Z_NULL, 0);
    unsigned long tot = 0;

    Local<Array> arr = Local<Array>::Cast(args[0]);

    int l = arr->Length();
    int i = 0;

    for (; i < l; i++) {
        Local<Object> obj = arr->Get(i)->ToObject();
        Local<Object> meta = obj->Get(SYM_META)->ToObject();

        Local<Value> objCrc = meta->Get(SYM_CRC);
        if (!Buffer::HasInstance(objCrc)) {
            char msg[40];
            sprintf(msg, "CRC32 is not a buffer at: %d", i);
            ThrowNodeError(msg);
            return Undefined();
        }

        Local<Object> bufCrc = objCrc->ToObject();

        unsigned long tmpCrc = reverseBytes((unsigned char *) Buffer::Data(bufCrc));
        unsigned long tmpLen = meta->Get(SYM_LENGTH)->Uint32Value();

        crc = crc32_combine(crc, tmpCrc, tmpLen);
        tot += tmpLen;
    }

    Local<Object> data = Object::New();
    data->Set(SYM_CRC, Buffer::New((char *) &crc, 4)->handle_);
    data->Set(SYM_LENGTH, Buffer::New((char *) &tot, 4)->handle_);

    return scope.Close(data);
}

static Handle<Value> uncompress (const Arguments &args) {
    HandleScope scope;

    if (args.Length() < 1) {
        return Undefined();
    }

    if (!Buffer::HasInstance(args[0])) {
        ThrowNodeError("First argument must be a Buffer");
        return Undefined();
    }

    z_stream strmUncompress;

    strmUncompress.zalloc=Z_NULL;
    strmUncompress.zfree=Z_NULL;
    strmUncompress.opaque=Z_NULL;
    strmUncompress.avail_in = 0;
    strmUncompress.next_in = Z_NULL;

    int rci = inflateInit2(&strmUncompress, WBITS);

    if (rci != Z_OK) {
        ThrowNodeError("zlib initialization error.");
        return Undefined();
    }

    Local<Object> bufferIn=args[0]->ToObject();

    strmUncompress.next_in = (Bytef*) Buffer::Data(bufferIn);
    strmUncompress.avail_in = Buffer::Length(bufferIn);

    Bytef  *bufferOut = NULL;
    uint32_t malloc_size=0;
    uint32_t currentPosition=0;

    int ret;

    do {
        Bytef *tmp = (Bytef*)malloc(CHUNK);
        strmUncompress.avail_out = CHUNK;
        strmUncompress.next_out = tmp;

        ret = inflate(&strmUncompress, Z_NO_FLUSH);
        assert(ret != Z_STREAM_ERROR);
        switch (ret) {
            case Z_NEED_DICT:
                ret = Z_DATA_ERROR;     /* and fall through */
            case Z_DATA_ERROR:
            case Z_MEM_ERROR:
                (void)inflateEnd(&strmUncompress);
                if (bufferOut!=NULL) {
                    free(bufferOut);
                }
                if (tmp!=NULL) {
                    free(tmp);
                }
                return Undefined();
        }

        uint32_t have = CHUNK - strmUncompress.avail_out;
        if (have>0) {
            bufferOut = (Bytef *) realloc(bufferOut, malloc_size+have);
            malloc_size=malloc_size+have;
        }

        memcpy(bufferOut+currentPosition, tmp, have);
        currentPosition+=have;
        free(tmp);
    } while (strmUncompress.avail_out == 0 && ret != Z_STREAM_END);

    inflateEnd(&strmUncompress);

    if (ret != Z_STREAM_END) {
        if (bufferOut!=NULL) {
            free(bufferOut);
        }
        return Undefined();
    }

    Buffer *BufferOut=Buffer::New((char *)bufferOut, malloc_size);
    free(bufferOut);

    return scope.Close(BufferOut->handle_);
}

extern "C" void init (Handle<Object> target) {
    SYM_BODY = NODE_PSYMBOL("body");
    SYM_RAW_BODY = NODE_PSYMBOL("rawBody");
    SYM_BOUNDARY = NODE_PSYMBOL("boundary");
    SYM_LEFT = NODE_PSYMBOL("left");
    SYM_RIGHT = NODE_PSYMBOL("right");
    SYM_LAST_BLOCK = NODE_PSYMBOL("lastBlock");
    SYM_TYPE = NODE_PSYMBOL("type");
    SYM_OFFSETS = NODE_PSYMBOL("offsets");
    SYM_LENGTH = NODE_PSYMBOL("length");
    SYM_RAW_LENGTH = NODE_PSYMBOL("rawLength");
    SYM_CRC = NODE_PSYMBOL("crc");
    SYM_META = NODE_PSYMBOL("meta");
    SYM_BUFFERS = NODE_PSYMBOL("buffers");
    SYM_HEADER = NODE_PSYMBOL("header");
    SYM_ODD = NODE_PSYMBOL("odd");
    tmpBody = (unsigned char *) malloc(CHUNK);

    char header[] = {0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
    Buffer *headerBuffer = Buffer::New(header, 10);

    char odd[] = {0x00, 0x00, 0xff, 0xff};
    Buffer *oddBuffer = Buffer::New(odd, 4);

    Handle<Object> buffers = Object::New();
    buffers->Set(SYM_HEADER, headerBuffer->handle_);
    buffers->Set(SYM_ODD, oddBuffer->handle_);

    target->Set(SYM_BUFFERS, buffers);

    NODE_SET_METHOD(target, "compress", compress);
    NODE_SET_METHOD(target, "uncompress", uncompress);
    NODE_SET_METHOD(target, "metaCompress", onet_compress);
    NODE_SET_METHOD(target, "getCrc", getCrc);
    NODE_SET_METHOD(target, "estimate", estimate);

}

NODE_MODULE(compress_buffer_bindings, init);

<|endoftext|>


<commit_before>#pragma once
#include "GameObject.h"
#include "frame.h"
#include "polygons.hpp"

class BG3D : public GameObject
{
public:
	BG3D( GameObject* parent )
		: GameObject( parent )
	{
		addChild( new CubeSolid( parent,
			Vector3( 0, -5, 4500),
			Vector3( 200, 5, 11000 ),
			TAN ) );
		/*
		addChild( new CubeSolid( parent,
			Vector3(0, -5, 5250),
			Vector3( 400, 5.1, 400 ),
			YELLOW ) );
		*/
	}
};
<commit_msg>바닥텍스쳐<commit_after>#pragma once
#include "GameObject.h"
#include "frame.h"
#include "polygons.hpp"

class BG3D : public GameObject
{
public:
	BG3D( GameObject* parent )
		: GameObject( parent )
	{
		addChild( new CubeSolidT( parent,
			Vector3( 0, -5, 4500),
			Vector3( 200, 5, 11000 ),
			TAN, "lion_body.jpg" ) );
		/*
		addChild( new CubeSolid( parent,
			Vector3(0, -5, 5250),
			Vector3( 400, 5.1, 400 ),
			YELLOW ) );
		*/
	}
};
<|endoftext|>