<commit_before>#include "Mescaline/Audio/IO/RemoteIODriver.hpp"
#include "Mescaline/Exception.hpp"

#include <AudioToolbox/AudioToolbox.h>

using namespace Mescaline::Audio::IO;

typedef boost::error_info<struct tag_OSStatus,OSStatus> OSStatusInfo;

#define MESCALINE_THROW_IF_ERROR(expr, msg) \
    do { \
        OSStatus err__ = expr; \
        if (err__ != 0) { \
            BOOST_THROW_EXCEPTION(Mescaline::Audio::IO::Exception() \
                    << Mescaline::ErrorInfoString(msg) \
                    << OSStatusInfo(err__)); \
        } \
    } while (false);

RemoteIODriver::RemoteIODriver(Client* client) throw (IO::Exception)
    : Driver(client)
    , m_numInputs(2)
    , m_numOutputs(2)
    , m_inputBuffers(0)
    , m_outputBuffers(0)
    , m_CAInputBuffers(0)
{
    // Initialize and configure the audio session
    MESCALINE_THROW_IF_ERROR(
        AudioSessionInitialize(NULL, NULL, InterruptionCallback, this)
      , "couldn't initialize audio session");

    MESCALINE_THROW_IF_ERROR(
        AudioSessionSetActive(true)
      , "couldn't set audio session active\n");

    UInt32 audioCategory = kAudioSessionCategory_PlayAndRecord;
    MESCALINE_THROW_IF_ERROR(
        AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory)
      , "couldn't set audio category");
    //MESCALINE_THROW_IF_ERROR(AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, propListener, self), "couldn't set property listener");

    Float64 hwSampleRate;
    UInt32 outSize = sizeof(hwSampleRate);
    MESCALINE_THROW_IF_ERROR(
        AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate, &outSize, &hwSampleRate)
      , "couldn't get hw sample rate");
    m_sampleRate = hwSampleRate;

    Float32 hwBufferSize;
    outSize = sizeof(hwBufferSize);
	MESCALINE_THROW_IF_ERROR(
	    AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &outSize, &hwBufferSize)
      , "couldn't set i/o buffer duration");

    outSize = sizeof(m_numInputs);
	MESCALINE_THROW_IF_ERROR(
	    AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputNumberChannels, &outSize, &m_numInputs)
      , "couldn't get hardware input channels");

    outSize = sizeof(m_numOutputs);
	MESCALINE_THROW_IF_ERROR(
	    AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputNumberChannels, &outSize, &m_numOutputs)
     ,  "couldn't get hardware output channels");

    // Float32 preferredBufferSize = .005;
    // MESCALINE_THROW_IF_ERROR(
    //     AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredBufferSize), &preferredBufferSize)
    //   , "couldn't set i/o buffer duration");

    // Open the output unit
    AudioComponentDescription desc;
    desc.componentType = kAudioUnitType_Output;
    desc.componentSubType = kAudioUnitSubType_RemoteIO;
    desc.componentManufacturer = kAudioUnitManufacturer_Apple;
    desc.componentFlags = 0;
    desc.componentFlagsMask = 0;

    AudioComponent comp = AudioComponentFindNext(NULL, &desc);

    MESCALINE_THROW_IF_ERROR(
        AudioComponentInstanceNew(comp, &m_rioUnit)
      , "couldn't open the remote I/O unit");

    UInt32 enableOutput = 1;
    MESCALINE_THROW_IF_ERROR(
        AudioUnitSetProperty(m_rioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableOutput, sizeof(enableOutput))
      , "couldn't enable output on the remote I/O unit");
    UInt32 enableInput = 1;
    MESCALINE_THROW_IF_ERROR(
        AudioUnitSetProperty(m_rioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableInput, sizeof(enableInput))
      , "couldn't enable input on the remote I/O unit");

    // This needs to be set before initializing the AudioUnit?
    m_bufferSize = (size_t)(m_sampleRate * hwBufferSize + .5);
    UInt32 maxFPS = m_bufferSize;
    MESCALINE_THROW_IF_ERROR(
        AudioUnitSetProperty(m_rioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, &maxFPS, sizeof(maxFPS))
      , "couldn't set AudioUnit buffer size");

    MESCALINE_THROW_IF_ERROR(
        AudioUnitSetProperty(m_rioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFPS, sizeof(maxFPS))
      , "couldn't set AudioUnit buffer size");

    // MESCALINE_THROW_IF_ERROR(
    //     AudioUnitGetProperty(m_rioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &m_bufferSize, &outSize)
    //   , "couldn't get AudioUnit buffer size");

    MESCALINE_THROW_IF_ERROR(
        AudioUnitInitialize(m_rioUnit)
      , "couldn't initialize the remote I/O unit");

    // Set input and output format
    AudioStreamBasicDescription auFormat;
    const size_t sampleSize = sizeof(sample_t);

    // Input format
    memset(&auFormat, 0, sizeof(auFormat));
    auFormat.mSampleRate = m_sampleRate;
    auFormat.mFormatID = kAudioFormatLinearPCM;
    auFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
    auFormat.mBitsPerChannel = 8 * sampleSize;
    auFormat.mChannelsPerFrame = m_numInputs;
    auFormat.mFramesPerPacket = 1;
    auFormat.mBytesPerPacket = sampleSize;
    auFormat.mBytesPerFrame = sampleSize;
    auFormat.mFormatFlags |= kAudioFormatFlagIsNonInterleaved;

    MESCALINE_THROW_IF_ERROR(
        AudioUnitSetProperty(m_rioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &auFormat, sizeof(auFormat))
      , "couldn't set the remote I/O unit's input client format");

    // Output format
    memset(&auFormat, 0, sizeof(auFormat));
    auFormat.mSampleRate = m_sampleRate;
    auFormat.mFormatID = kAudioFormatLinearPCM;
    auFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
    auFormat.mBitsPerChannel = 8 * sampleSize;
    auFormat.mChannelsPerFrame = m_numInputs;
    auFormat.mFramesPerPacket = 1;
    auFormat.mBytesPerPacket = sampleSize;
    auFormat.mBytesPerFrame = sampleSize;
    auFormat.mFormatFlags |= kAudioFormatFlagIsNonInterleaved;

    MESCALINE_THROW_IF_ERROR(
        AudioUnitSetProperty(m_rioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &auFormat, sizeof(auFormat))
      , "couldn't set the remote I/O unit's output client format");

    // outSize = sizeof(outFormat);
    // MESCALINE_THROW_IF_ERROR(
    //     AudioUnitGetProperty(m_rioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &outFormat, &outSize)
    //   , "couldn't get the remote I/O unit's output client format");
    // outFormat.Print();

    // Set render callback
    AURenderCallbackStruct inputProc;
    inputProc.inputProc = RenderCallback;
    inputProc.inputProcRefCon = this;

    MESCALINE_THROW_IF_ERROR(
        AudioUnitSetProperty(m_rioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &inputProc, sizeof(inputProc))
      , "couldn't set remote i/o render callback");

    // Initialize I/O buffers
    m_inputBuffers = new float*[m_numInputs];
    m_outputBuffers = new float*[m_numOutputs];
    m_CAInputBuffers = new AudioBufferList[m_numInputs];
    m_CAInputBuffers->mNumberBuffers = m_numInputs;

    for (size_t i = 0; i < m_numInputs; i++) {
        m_inputBuffers[i] =
            Mescaline::Memory::allocAlignedOf<sample_t,Mescaline::Memory::kSIMDAlignment>(m_bufferSize);
        m_CAInputBuffers->mBuffers[i].mNumberChannels = 1;
        m_CAInputBuffers->mBuffers[i].mDataByteSize = m_bufferSize * sizeof(sample_t);
        m_CAInputBuffers->mBuffers[i].mData = m_inputBuffers[i];
    }

    // Initialize client
    client()->configure(*this);
}

RemoteIODriver::~RemoteIODriver() throw (IO::Exception)
{
    // Free input buffer memory
    for (size_t i=0; i < m_numInputs; i++) {
        Mescaline::Memory::free(m_inputBuffers[i]);
    }
    // Free buffer pointer arrays
    delete [] m_inputBuffers;
    delete [] m_outputBuffers;
    delete [] m_CAInputBuffers;
}

void RemoteIODriver::start()
{
    MESCALINE_THROW_IF_ERROR(AudioOutputUnitStart(m_rioUnit), "couldn't start remote i/o unit");
}

void RemoteIODriver::stop()
{
    MESCALINE_THROW_IF_ERROR(AudioOutputUnitStop(m_rioUnit), "couldn't start remote i/o unit");
}

void RemoteIODriver::InterruptionCallback(void *inClientData, UInt32 inInterruption)
{
    RemoteIODriver* self = static_cast<RemoteIODriver*>(inClientData);

    if (inInterruption == kAudioSessionEndInterruption) {
        // make sure we are again the active session
        MESCALINE_THROW_IF_ERROR(AudioSessionSetActive(true), "couldn't set audio session active");
        self->start();
    }

    if (inInterruption == kAudioSessionBeginInterruption) {
        self->stop();
    }
}

OSStatus RemoteIODriver::RenderCallback(
    void*                       inRefCon,
    AudioUnitRenderActionFlags* ioActionFlags,
    const AudioTimeStamp*       inTimeStamp,
    UInt32                      inBusNumber,
    UInt32                      inNumberFrames,
    AudioBufferList*            ioData)
{
    RemoteIODriver* self = static_cast<RemoteIODriver*>(inRefCon);

    // Gather input
    OSStatus err = AudioUnitRender(self->m_rioUnit, ioActionFlags, inTimeStamp, 1, inNumberFrames, self->m_CAInputBuffers);
    if (err) return err;

    // Set up output buffers
    for (size_t i = 0; i < self->numOutputs(); i++) {
        self->m_outputBuffers[i] = (float*)ioData->mBuffers[i].mData;
    }

    // Run DSP graph
    self->client()->process(inNumberFrames, self->m_inputBuffers, self->m_outputBuffers);

    return noErr;
}
<commit_msg>Fix shadowing of function by variable<commit_after>#include "Mescaline/Audio/IO/RemoteIODriver.hpp"
#include "Mescaline/Exception.hpp"

#include <AudioToolbox/AudioToolbox.h>

using namespace Mescaline::Audio::IO;

typedef boost::error_info<struct tag_OSStatus,OSStatus> OSStatusInfo;

#define MESCALINE_THROW_IF_ERROR(expr, msg) \
    do { \
        OSStatus err__ = expr; \
        if (err__ != 0) { \
            BOOST_THROW_EXCEPTION(Mescaline::Audio::IO::Exception() \
                    << Mescaline::ErrorInfoString(msg) \
                    << OSStatusInfo(err__)); \
        } \
    } while (false);

RemoteIODriver::RemoteIODriver(Client* client) throw (IO::Exception)
    : Driver(client)
    , m_numInputs(2)
    , m_numOutputs(2)
    , m_inputBuffers(0)
    , m_outputBuffers(0)
    , m_CAInputBuffers(0)
{
    // Initialize and configure the audio session
    MESCALINE_THROW_IF_ERROR(
        AudioSessionInitialize(NULL, NULL, InterruptionCallback, this)
      , "couldn't initialize audio session");

    MESCALINE_THROW_IF_ERROR(
        AudioSessionSetActive(true)
      , "couldn't set audio session active\n");

    UInt32 audioCategory = kAudioSessionCategory_PlayAndRecord;
    MESCALINE_THROW_IF_ERROR(
        AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(audioCategory), &audioCategory)
      , "couldn't set audio category");
    //MESCALINE_THROW_IF_ERROR(AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange, propListener, self), "couldn't set property listener");

    Float64 hwSampleRate;
    UInt32 outSize = sizeof(hwSampleRate);
    MESCALINE_THROW_IF_ERROR(
        AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareSampleRate, &outSize, &hwSampleRate)
      , "couldn't get hw sample rate");
    m_sampleRate = hwSampleRate;

    Float32 hwBufferSize;
    outSize = sizeof(hwBufferSize);
	MESCALINE_THROW_IF_ERROR(
	    AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareIOBufferDuration, &outSize, &hwBufferSize)
      , "couldn't set i/o buffer duration");

    outSize = sizeof(m_numInputs);
	MESCALINE_THROW_IF_ERROR(
	    AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareInputNumberChannels, &outSize, &m_numInputs)
      , "couldn't get hardware input channels");

    outSize = sizeof(m_numOutputs);
	MESCALINE_THROW_IF_ERROR(
	    AudioSessionGetProperty(kAudioSessionProperty_CurrentHardwareOutputNumberChannels, &outSize, &m_numOutputs)
     ,  "couldn't get hardware output channels");

    // Float32 preferredBufferSize = .005;
    // MESCALINE_THROW_IF_ERROR(
    //     AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration, sizeof(preferredBufferSize), &preferredBufferSize)
    //   , "couldn't set i/o buffer duration");

    // Open the output unit
    AudioComponentDescription desc;
    desc.componentType = kAudioUnitType_Output;
    desc.componentSubType = kAudioUnitSubType_RemoteIO;
    desc.componentManufacturer = kAudioUnitManufacturer_Apple;
    desc.componentFlags = 0;
    desc.componentFlagsMask = 0;

    AudioComponent comp = AudioComponentFindNext(NULL, &desc);

    MESCALINE_THROW_IF_ERROR(
        AudioComponentInstanceNew(comp, &m_rioUnit)
      , "couldn't open the remote I/O unit");

    UInt32 enableOutput = 1;
    MESCALINE_THROW_IF_ERROR(
        AudioUnitSetProperty(m_rioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableOutput, sizeof(enableOutput))
      , "couldn't enable output on the remote I/O unit");
    UInt32 enableInput = 1;
    MESCALINE_THROW_IF_ERROR(
        AudioUnitSetProperty(m_rioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableInput, sizeof(enableInput))
      , "couldn't enable input on the remote I/O unit");

    // This needs to be set before initializing the AudioUnit?
    m_bufferSize = (size_t)(m_sampleRate * hwBufferSize + .5);
    UInt32 maxFPS = m_bufferSize;
    MESCALINE_THROW_IF_ERROR(
        AudioUnitSetProperty(m_rioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 1, &maxFPS, sizeof(maxFPS))
      , "couldn't set AudioUnit buffer size");

    MESCALINE_THROW_IF_ERROR(
        AudioUnitSetProperty(m_rioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFPS, sizeof(maxFPS))
      , "couldn't set AudioUnit buffer size");

    // MESCALINE_THROW_IF_ERROR(
    //     AudioUnitGetProperty(m_rioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &m_bufferSize, &outSize)
    //   , "couldn't get AudioUnit buffer size");

    MESCALINE_THROW_IF_ERROR(
        AudioUnitInitialize(m_rioUnit)
      , "couldn't initialize the remote I/O unit");

    // Set input and output format
    AudioStreamBasicDescription auFormat;
    const size_t sampleSize = sizeof(sample_t);

    // Input format
    memset(&auFormat, 0, sizeof(auFormat));
    auFormat.mSampleRate = m_sampleRate;
    auFormat.mFormatID = kAudioFormatLinearPCM;
    auFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
    auFormat.mBitsPerChannel = 8 * sampleSize;
    auFormat.mChannelsPerFrame = m_numInputs;
    auFormat.mFramesPerPacket = 1;
    auFormat.mBytesPerPacket = sampleSize;
    auFormat.mBytesPerFrame = sampleSize;
    auFormat.mFormatFlags |= kAudioFormatFlagIsNonInterleaved;

    MESCALINE_THROW_IF_ERROR(
        AudioUnitSetProperty(m_rioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &auFormat, sizeof(auFormat))
      , "couldn't set the remote I/O unit's input client format");

    // Output format
    memset(&auFormat, 0, sizeof(auFormat));
    auFormat.mSampleRate = m_sampleRate;
    auFormat.mFormatID = kAudioFormatLinearPCM;
    auFormat.mFormatFlags = kAudioFormatFlagsNativeFloatPacked;
    auFormat.mBitsPerChannel = 8 * sampleSize;
    auFormat.mChannelsPerFrame = m_numInputs;
    auFormat.mFramesPerPacket = 1;
    auFormat.mBytesPerPacket = sampleSize;
    auFormat.mBytesPerFrame = sampleSize;
    auFormat.mFormatFlags |= kAudioFormatFlagIsNonInterleaved;

    MESCALINE_THROW_IF_ERROR(
        AudioUnitSetProperty(m_rioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &auFormat, sizeof(auFormat))
      , "couldn't set the remote I/O unit's output client format");

    // outSize = sizeof(outFormat);
    // MESCALINE_THROW_IF_ERROR(
    //     AudioUnitGetProperty(m_rioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &outFormat, &outSize)
    //   , "couldn't get the remote I/O unit's output client format");
    // outFormat.Print();

    // Set render callback
    AURenderCallbackStruct inputProc;
    inputProc.inputProc = RenderCallback;
    inputProc.inputProcRefCon = this;

    MESCALINE_THROW_IF_ERROR(
        AudioUnitSetProperty(m_rioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &inputProc, sizeof(inputProc))
      , "couldn't set remote i/o render callback");

    // Initialize I/O buffers
    m_inputBuffers = new float*[m_numInputs];
    m_outputBuffers = new float*[m_numOutputs];
    m_CAInputBuffers = new AudioBufferList[m_numInputs];
    m_CAInputBuffers->mNumberBuffers = m_numInputs;

    for (size_t i = 0; i < m_numInputs; i++) {
        m_inputBuffers[i] =
            Mescaline::Memory::allocAlignedOf<sample_t,Mescaline::Memory::kSIMDAlignment>(m_bufferSize);
        m_CAInputBuffers->mBuffers[i].mNumberChannels = 1;
        m_CAInputBuffers->mBuffers[i].mDataByteSize = m_bufferSize * sizeof(sample_t);
        m_CAInputBuffers->mBuffers[i].mData = m_inputBuffers[i];
    }

    // Initialize client
    client->configure(*this);
}

RemoteIODriver::~RemoteIODriver() throw (IO::Exception)
{
    // Free input buffer memory
    for (size_t i=0; i < m_numInputs; i++) {
        Mescaline::Memory::free(m_inputBuffers[i]);
    }
    // Free buffer pointer arrays
    delete [] m_inputBuffers;
    delete [] m_outputBuffers;
    delete [] m_CAInputBuffers;
}

void RemoteIODriver::start()
{
    MESCALINE_THROW_IF_ERROR(AudioOutputUnitStart(m_rioUnit), "couldn't start remote i/o unit");
}

void RemoteIODriver::stop()
{
    MESCALINE_THROW_IF_ERROR(AudioOutputUnitStop(m_rioUnit), "couldn't start remote i/o unit");
}

void RemoteIODriver::InterruptionCallback(void *inClientData, UInt32 inInterruption)
{
    RemoteIODriver* self = static_cast<RemoteIODriver*>(inClientData);

    if (inInterruption == kAudioSessionEndInterruption) {
        // make sure we are again the active session
        MESCALINE_THROW_IF_ERROR(AudioSessionSetActive(true), "couldn't set audio session active");
        self->start();
    }

    if (inInterruption == kAudioSessionBeginInterruption) {
        self->stop();
    }
}

OSStatus RemoteIODriver::RenderCallback(
    void*                       inRefCon,
    AudioUnitRenderActionFlags* ioActionFlags,
    const AudioTimeStamp*       inTimeStamp,
    UInt32                      inBusNumber,
    UInt32                      inNumberFrames,
    AudioBufferList*            ioData)
{
    RemoteIODriver* self = static_cast<RemoteIODriver*>(inRefCon);

    // Gather input
    OSStatus err = AudioUnitRender(self->m_rioUnit, ioActionFlags, inTimeStamp, 1, inNumberFrames, self->m_CAInputBuffers);
    if (err) return err;

    // Set up output buffers
    for (size_t i = 0; i < self->numOutputs(); i++) {
        self->m_outputBuffers[i] = (float*)ioData->mBuffers[i].mData;
    }

    // Run DSP graph
    self->client()->process(inNumberFrames, self->m_inputBuffers, self->m_outputBuffers);

    return noErr;
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2016, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include "Compression.h"

#include <folly/Format.h>
#include <folly/Memory.h>
#include <folly/Portability.h>
#include <folly/io/IOBuf.h>

#if FOLLY_HAVE_LIBLZ4
#include <lz4.h>
#endif // FOLLY_HAVE_LIBLZ4

#include "mcrouter/lib/IovecCursor.h"
#include "mcrouter/lib/Lz4Immutable.h"

namespace facebook {
namespace memcache {

CompressionCodec::CompressionCodec(
    CompressionCodecType type,
    uint32_t id,
    CompressionCodecOptions options)
    : type_(type), id_(id), options_(options) {}

std::unique_ptr<folly::IOBuf> CompressionCodec::compress(
    const folly::IOBuf& data) {
  auto iov = data.getIov();
  return compress(iov.data(), iov.size());
}
std::unique_ptr<folly::IOBuf> CompressionCodec::compress(
    const void* data,
    size_t len) {
  struct iovec iov;
  iov.iov_base = const_cast<void*>(data);
  iov.iov_len = len;
  return compress(&iov, 1);
}

std::unique_ptr<folly::IOBuf> CompressionCodec::uncompress(
    const folly::IOBuf& data,
    size_t uncompressedLength) {
  auto iov = data.getIov();
  return uncompress(iov.data(), iov.size(), uncompressedLength);
}
std::unique_ptr<folly::IOBuf> CompressionCodec::uncompress(
    const void* data,
    size_t len,
    size_t uncompressedLength) {
  struct iovec iov;
  iov.iov_base = const_cast<void*>(data);
  iov.iov_len = len;
  return uncompress(&iov, 1, uncompressedLength);
}

namespace {

std::unique_ptr<folly::IOBuf> wrapIovec(
    const struct iovec* iov,
    size_t iovcnt) {
  if (iovcnt == 0) {
    return nullptr;
  }

  auto head = folly::IOBuf::wrapBuffer(iov[0].iov_base, iov[0].iov_len);
  for (size_t i = iovcnt - 1; i > 0; --i) {
    head->appendChain(
        folly::IOBuf::wrapBuffer(iov[i].iov_base, iov[i].iov_len));
  }
  return head;
}

folly::IOBuf
coalesceSlow(const struct iovec* iov, size_t iovcnt, size_t destCapacity) {
  folly::IOBuf buffer(folly::IOBuf::CREATE, destCapacity);
  for (size_t i = 0; i < iovcnt; ++i) {
    std::memcpy(buffer.writableTail(), iov[i].iov_base, iov[i].iov_len);
    buffer.append(iov[i].iov_len);
  }
  assert(buffer.length() <= destCapacity);
  return buffer;
}

folly::IOBuf
coalesce(const struct iovec* iov, size_t iovcnt, size_t destCapacity) {
  if (iovcnt == 1) {
    return folly::IOBuf(
        folly::IOBuf::WRAP_BUFFER, iov[0].iov_base, iov[0].iov_len);
  }
  return coalesceSlow(iov, iovcnt, destCapacity);
}

/************************
 * No Compression Codec *
 ************************/
class NoCompressionCodec : public CompressionCodec {
 public:
  NoCompressionCodec(
      std::unique_ptr<folly::IOBuf> dictionary,
      uint32_t id,
      CompressionCodecOptions options)
      : CompressionCodec(CompressionCodecType::NO_COMPRESSION, id, options) {}

  std::unique_ptr<folly::IOBuf> compress(const struct iovec* iov, size_t iovcnt)
      override final {
    return wrapIovec(iov, iovcnt);
  }
  std::unique_ptr<folly::IOBuf> uncompress(
      const struct iovec* iov,
      size_t iovcnt,
      size_t uncompressedLength = 0) override final {
    return wrapIovec(iov, iovcnt);
  }
};

/*************************
 * LZ4 Compression Codec *
 *************************/
#if FOLLY_HAVE_LIBLZ4
class Lz4CompressionCodec : public CompressionCodec {
 public:
  Lz4CompressionCodec(
      std::unique_ptr<folly::IOBuf> dictionary,
      uint32_t id,
      CompressionCodecOptions options);

  std::unique_ptr<folly::IOBuf> compress(const struct iovec* iov, size_t iovcnt)
      override final;
  std::unique_ptr<folly::IOBuf> uncompress(
      const struct iovec* iov,
      size_t iovcnt,
      size_t uncompressedLength = 0) override final;

 private:
  static constexpr size_t kMaxDictionarySize = 64 * 1024;
  static constexpr size_t kLargeDataThreshold = 2 * 1024;

  const std::unique_ptr<folly::IOBuf> dictionary_;
  const Lz4Immutable lz4Immutable_;
  LZ4_stream_t* lz4Stream_{nullptr};

  FOLLY_NOINLINE std::unique_ptr<folly::IOBuf> compressLargeData(
      folly::IOBuf data);
};

Lz4CompressionCodec::Lz4CompressionCodec(
    std::unique_ptr<folly::IOBuf> dictionary,
    uint32_t id,
    CompressionCodecOptions options)
    : CompressionCodec(CompressionCodecType::LZ4, id, options),
      dictionary_(std::move(dictionary)),
      lz4Immutable_(dictionary_->clone()),
      lz4Stream_(LZ4_createStream()) {
  if (!lz4Stream_) {
    throw std::runtime_error("Failed to allocate LZ4_stream_t");
  }

  int res = LZ4_loadDict(
      lz4Stream_,
      reinterpret_cast<const char*>(dictionary_->data()),
      dictionary_->length());
  if (res != dictionary_->length()) {
    throw std::runtime_error(
        folly::sformat(
            "LZ4 codec: Failed to load dictionary. Return code: {}", res));
  }
}

std::unique_ptr<folly::IOBuf> Lz4CompressionCodec::compress(
    const struct iovec* iov,
    size_t iovcnt) {
  assert(iov);

  auto size = IovecCursor::computeTotalLength(iov, iovcnt);
  if (size < kLargeDataThreshold) {
    return lz4Immutable_.compress(iov, iovcnt);
  }
  return compressLargeData(coalesce(iov, iovcnt, size));
}

std::unique_ptr<folly::IOBuf> Lz4CompressionCodec::compressLargeData(
    folly::IOBuf data) {
  LZ4_stream_t lz4StreamCopy = *lz4Stream_;

  size_t compressBound = LZ4_compressBound(data.length());
  auto buffer = folly::IOBuf::create(compressBound);

  int compressedSize = LZ4_compress_fast_continue(
      &lz4StreamCopy,
      reinterpret_cast<const char*>(data.data()),
      reinterpret_cast<char*>(buffer->writableTail()),
      data.length(),
      compressBound,
      1);

  // compression is guaranteed to work as we use
  // LZ4_compressBound as destBuffer size.
  assert(compressedSize > 0);

  buffer->append(compressedSize);
  return buffer;
}

std::unique_ptr<folly::IOBuf> Lz4CompressionCodec::uncompress(
    const struct iovec* iov,
    size_t iovcnt,
    size_t uncompressedLength) {
  if (uncompressedLength == 0) {
    throw std::invalid_argument("LZ4 codec: uncompressed length required");
  }

  auto data =
      coalesce(iov, iovcnt, IovecCursor::computeTotalLength(iov, iovcnt));
  auto buffer = folly::IOBuf::create(uncompressedLength);
  int bytesWritten = LZ4_decompress_safe_usingDict(
      reinterpret_cast<const char*>(data.data()),
      reinterpret_cast<char*>(buffer->writableTail()),
      data.length(), buffer->tailroom(),
      reinterpret_cast<const char*>(dictionary_->data()),
      dictionary_->length());

  // Should either fail completely or decompress everything.
  assert(bytesWritten <= 0 || bytesWritten == uncompressedLength);
  if (bytesWritten <= 0) {
    throw std::runtime_error("LZ4 codec: decompression returned invalid value");
  }

  buffer->append(bytesWritten);
  return buffer;
}
#endif // FOLLY_HAVE_LIBLZ4

} // anonymous namespace

/*****************************
 * Compression Codec Factory *
 *****************************/
std::unique_ptr<CompressionCodec> createCompressionCodec(
    CompressionCodecType type,
    std::unique_ptr<folly::IOBuf> dictionary,
    uint32_t id,
    CompressionCodecOptions options) {
  switch (type) {
    case CompressionCodecType::NO_COMPRESSION:
      return folly::make_unique<NoCompressionCodec>(
          std::move(dictionary), id, options);
    case CompressionCodecType::LZ4:
#if FOLLY_HAVE_LIBLZ4
      return folly::make_unique<Lz4CompressionCodec>(
          std::move(dictionary), id, options);
#else
      LOG(ERROR) << "LZ4 is not available. Returning nullptr.";
      return nullptr;
#endif // FOLLY_HAVE_LIBLZ4
  }
  return nullptr;
}

} // memcache
} // facebook
<commit_msg>Fix memory leak in Lz4CompressionCodec<commit_after>/*
 *  Copyright (c) 2016, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */
#include "Compression.h"

#include <folly/Format.h>
#include <folly/Memory.h>
#include <folly/Portability.h>
#include <folly/io/IOBuf.h>

#if FOLLY_HAVE_LIBLZ4
#include <lz4.h>
#endif // FOLLY_HAVE_LIBLZ4

#include "mcrouter/lib/IovecCursor.h"
#include "mcrouter/lib/Lz4Immutable.h"

namespace facebook {
namespace memcache {

CompressionCodec::CompressionCodec(
    CompressionCodecType type,
    uint32_t id,
    CompressionCodecOptions options)
    : type_(type), id_(id), options_(options) {}

std::unique_ptr<folly::IOBuf> CompressionCodec::compress(
    const folly::IOBuf& data) {
  auto iov = data.getIov();
  return compress(iov.data(), iov.size());
}
std::unique_ptr<folly::IOBuf> CompressionCodec::compress(
    const void* data,
    size_t len) {
  struct iovec iov;
  iov.iov_base = const_cast<void*>(data);
  iov.iov_len = len;
  return compress(&iov, 1);
}

std::unique_ptr<folly::IOBuf> CompressionCodec::uncompress(
    const folly::IOBuf& data,
    size_t uncompressedLength) {
  auto iov = data.getIov();
  return uncompress(iov.data(), iov.size(), uncompressedLength);
}
std::unique_ptr<folly::IOBuf> CompressionCodec::uncompress(
    const void* data,
    size_t len,
    size_t uncompressedLength) {
  struct iovec iov;
  iov.iov_base = const_cast<void*>(data);
  iov.iov_len = len;
  return uncompress(&iov, 1, uncompressedLength);
}

namespace {

std::unique_ptr<folly::IOBuf> wrapIovec(
    const struct iovec* iov,
    size_t iovcnt) {
  if (iovcnt == 0) {
    return nullptr;
  }

  auto head = folly::IOBuf::wrapBuffer(iov[0].iov_base, iov[0].iov_len);
  for (size_t i = iovcnt - 1; i > 0; --i) {
    head->appendChain(
        folly::IOBuf::wrapBuffer(iov[i].iov_base, iov[i].iov_len));
  }
  return head;
}

folly::IOBuf
coalesceSlow(const struct iovec* iov, size_t iovcnt, size_t destCapacity) {
  folly::IOBuf buffer(folly::IOBuf::CREATE, destCapacity);
  for (size_t i = 0; i < iovcnt; ++i) {
    std::memcpy(buffer.writableTail(), iov[i].iov_base, iov[i].iov_len);
    buffer.append(iov[i].iov_len);
  }
  assert(buffer.length() <= destCapacity);
  return buffer;
}

folly::IOBuf
coalesce(const struct iovec* iov, size_t iovcnt, size_t destCapacity) {
  if (iovcnt == 1) {
    return folly::IOBuf(
        folly::IOBuf::WRAP_BUFFER, iov[0].iov_base, iov[0].iov_len);
  }
  return coalesceSlow(iov, iovcnt, destCapacity);
}

/************************
 * No Compression Codec *
 ************************/
class NoCompressionCodec : public CompressionCodec {
 public:
  NoCompressionCodec(
      std::unique_ptr<folly::IOBuf> dictionary,
      uint32_t id,
      CompressionCodecOptions options)
      : CompressionCodec(CompressionCodecType::NO_COMPRESSION, id, options) {}

  std::unique_ptr<folly::IOBuf> compress(const struct iovec* iov, size_t iovcnt)
      override final {
    return wrapIovec(iov, iovcnt);
  }
  std::unique_ptr<folly::IOBuf> uncompress(
      const struct iovec* iov,
      size_t iovcnt,
      size_t uncompressedLength = 0) override final {
    return wrapIovec(iov, iovcnt);
  }
};

/*************************
 * LZ4 Compression Codec *
 *************************/
#if FOLLY_HAVE_LIBLZ4
class Lz4CompressionCodec : public CompressionCodec {
 public:
  Lz4CompressionCodec(
      std::unique_ptr<folly::IOBuf> dictionary,
      uint32_t id,
      CompressionCodecOptions options);

  std::unique_ptr<folly::IOBuf> compress(const struct iovec* iov, size_t iovcnt)
      override final;
  std::unique_ptr<folly::IOBuf> uncompress(
      const struct iovec* iov,
      size_t iovcnt,
      size_t uncompressedLength = 0) override final;

  ~Lz4CompressionCodec() {
    LZ4_freeStream(lz4Stream_);
  }

 private:
  static constexpr size_t kMaxDictionarySize = 64 * 1024;
  static constexpr size_t kLargeDataThreshold = 2 * 1024;

  const std::unique_ptr<folly::IOBuf> dictionary_;
  const Lz4Immutable lz4Immutable_;
  LZ4_stream_t* lz4Stream_{nullptr};

  FOLLY_NOINLINE std::unique_ptr<folly::IOBuf> compressLargeData(
      folly::IOBuf data);
};

Lz4CompressionCodec::Lz4CompressionCodec(
    std::unique_ptr<folly::IOBuf> dictionary,
    uint32_t id,
    CompressionCodecOptions options)
    : CompressionCodec(CompressionCodecType::LZ4, id, options),
      dictionary_(std::move(dictionary)),
      lz4Immutable_(dictionary_->clone()),
      lz4Stream_(LZ4_createStream()) {
  if (!lz4Stream_) {
    throw std::runtime_error("Failed to allocate LZ4_stream_t");
  }

  int res = LZ4_loadDict(
      lz4Stream_,
      reinterpret_cast<const char*>(dictionary_->data()),
      dictionary_->length());
  if (res != dictionary_->length()) {
    throw std::runtime_error(
        folly::sformat(
            "LZ4 codec: Failed to load dictionary. Return code: {}", res));
  }
}

std::unique_ptr<folly::IOBuf> Lz4CompressionCodec::compress(
    const struct iovec* iov,
    size_t iovcnt) {
  assert(iov);

  auto size = IovecCursor::computeTotalLength(iov, iovcnt);
  if (size < kLargeDataThreshold) {
    return lz4Immutable_.compress(iov, iovcnt);
  }
  return compressLargeData(coalesce(iov, iovcnt, size));
}

std::unique_ptr<folly::IOBuf> Lz4CompressionCodec::compressLargeData(
    folly::IOBuf data) {
  LZ4_stream_t lz4StreamCopy = *lz4Stream_;

  size_t compressBound = LZ4_compressBound(data.length());
  auto buffer = folly::IOBuf::create(compressBound);

  int compressedSize = LZ4_compress_fast_continue(
      &lz4StreamCopy,
      reinterpret_cast<const char*>(data.data()),
      reinterpret_cast<char*>(buffer->writableTail()),
      data.length(),
      compressBound,
      1);

  // compression is guaranteed to work as we use
  // LZ4_compressBound as destBuffer size.
  assert(compressedSize > 0);

  buffer->append(compressedSize);
  return buffer;
}

std::unique_ptr<folly::IOBuf> Lz4CompressionCodec::uncompress(
    const struct iovec* iov,
    size_t iovcnt,
    size_t uncompressedLength) {
  if (uncompressedLength == 0) {
    throw std::invalid_argument("LZ4 codec: uncompressed length required");
  }

  auto data =
      coalesce(iov, iovcnt, IovecCursor::computeTotalLength(iov, iovcnt));
  auto buffer = folly::IOBuf::create(uncompressedLength);
  int bytesWritten = LZ4_decompress_safe_usingDict(
      reinterpret_cast<const char*>(data.data()),
      reinterpret_cast<char*>(buffer->writableTail()),
      data.length(), buffer->tailroom(),
      reinterpret_cast<const char*>(dictionary_->data()),
      dictionary_->length());

  // Should either fail completely or decompress everything.
  assert(bytesWritten <= 0 || bytesWritten == uncompressedLength);
  if (bytesWritten <= 0) {
    throw std::runtime_error("LZ4 codec: decompression returned invalid value");
  }

  buffer->append(bytesWritten);
  return buffer;
}
#endif // FOLLY_HAVE_LIBLZ4

} // anonymous namespace

/*****************************
 * Compression Codec Factory *
 *****************************/
std::unique_ptr<CompressionCodec> createCompressionCodec(
    CompressionCodecType type,
    std::unique_ptr<folly::IOBuf> dictionary,
    uint32_t id,
    CompressionCodecOptions options) {
  switch (type) {
    case CompressionCodecType::NO_COMPRESSION:
      return folly::make_unique<NoCompressionCodec>(
          std::move(dictionary), id, options);
    case CompressionCodecType::LZ4:
#if FOLLY_HAVE_LIBLZ4
      return folly::make_unique<Lz4CompressionCodec>(
          std::move(dictionary), id, options);
#else
      LOG(ERROR) << "LZ4 is not available. Returning nullptr.";
      return nullptr;
#endif // FOLLY_HAVE_LIBLZ4
  }
  return nullptr;
}

} // memcache
} // facebook
<|endoftext|>


<commit_before>/*
 * PtwiseLinearTransferLayer.cpp
 *
 *  Created on: July 24, 2015
 *      Author: pschultz
 */

#include "PtwiseLinearTransferLayer.hpp"
#include "updateStateFunctions.h"
#include <limits>

#ifdef __cplusplus
extern "C" {
#endif

void PtwiseLinearTransferLayer_update_state(
    const int nbatch,
    const int numNeurons,
    const int nx,
    const int ny,
    const int nf,
    const int lt,
    const int rt,
    const int dn,
    const int up,

    float * V,
    int numVertices,
    float * verticesV,
    float * verticesA,
    float * slopes,
    int num_channels,
    float * GSynHead,
    float * activity);

#ifdef __cplusplus
}
#endif

namespace PV {

PtwiseLinearTransferLayer::PtwiseLinearTransferLayer() {
   initialize_base();
}

PtwiseLinearTransferLayer::PtwiseLinearTransferLayer(const char * name, HyPerCol * hc) {
   initialize_base();
   initialize(name, hc);
//#ifdef PV_USE_OPENCL
//   if(gpuAccelerateFlag)
//      initializeGPU();
//#endif
}  // end PtwiseLinearTransferLayer::PtwiseLinearTransferLayer(const char *, HyPerCol *)

PtwiseLinearTransferLayer::~PtwiseLinearTransferLayer() {
   free(verticesV); verticesV = NULL;
   free(verticesA); verticesA = NULL;
   free(slopes); slopes = NULL;
}

int PtwiseLinearTransferLayer::initialize_base() {
   numVertices = 0;
   verticesV = NULL;
   verticesA = NULL;
   slopes = NULL;
   slopeNegInf = 1.0f;
   slopePosInf = 1.0f;
   return PV_SUCCESS;
}

int PtwiseLinearTransferLayer::initialize(const char * name, HyPerCol * hc) {
   int status = HyPerLayer::initialize(name, hc);
   assert(status == PV_SUCCESS);

   status |= checkVertices();
   status |= setSlopes();
//#ifdef PV_USE_OPENCL
//   numEvents=NUM_ANN_EVENTS;
//#endif
   return status;
}

int PtwiseLinearTransferLayer::ioParamsFillGroup(enum ParamsIOFlag ioFlag) {
   int status = HyPerLayer::ioParamsFillGroup(ioFlag);

   assert(numVertices==0);
   ioParam_verticesV(ioFlag);
   ioParam_verticesA(ioFlag);
   assert(numVertices!=0);

   ioParam_slopeNegInf(ioFlag);
   ioParam_slopePosInf(ioFlag);

   ioParam_clearGSynInterval(ioFlag);

   return status;
}

void PtwiseLinearTransferLayer::ioParam_verticesV(enum ParamsIOFlag ioFlag) {
   int numVerticesV;
   this->getParent()->ioParamArray(ioFlag, this->getName(), "verticesV", &verticesV, &numVerticesV);
   if (ioFlag==PARAMS_IO_READ && numVerticesV==0) {
      if (this->getParent()->columnId()==0) {
         fprintf(stderr,
               "%s \"%s\" error: verticesV cannot be empty\n",
               this->getParent()->parameters()->groupKeywordFromName(this->getName()),
               this->getName());
      }
      MPI_Barrier(this->getParent()->icCommunicator()->communicator());
      exit(EXIT_FAILURE);
   }
   if (numVertices !=0 && numVerticesV != numVertices) {
      if (this->getParent()->columnId()==0) {
         fprintf(stderr,
               "%s \"%s\" error: verticesV (%d elements) and verticesA (%d elements) must have the same lengths.\n",
               this->getParent()->parameters()->groupKeywordFromName(this->getName()),
               this->getName(),
               numVerticesV, numVertices);
      }
      MPI_Barrier(this->getParent()->icCommunicator()->communicator());
      exit(EXIT_FAILURE);
   }
   assert(numVertices==0 || numVertices==numVerticesV);
   numVertices = numVerticesV;
}

void PtwiseLinearTransferLayer::ioParam_verticesA(enum ParamsIOFlag ioFlag) {
   int numVerticesA;
   this->getParent()->ioParamArray(ioFlag, this->getName(), "verticesA", &verticesA, &numVerticesA);
   if (ioFlag==PARAMS_IO_READ && numVerticesA==0) {
      if (this->getParent()->columnId()==0) {
         fprintf(stderr,
               "%s \"%s\" error: verticesA cannot be empty\n",
               this->getParent()->parameters()->groupKeywordFromName(this->getName()),
               this->getName());
      }
      MPI_Barrier(this->getParent()->icCommunicator()->communicator());
      exit(EXIT_FAILURE);
   }
   if (numVertices !=0 && numVerticesA != numVertices) {
      if (this->getParent()->columnId()==0) {
         fprintf(stderr,
               "%s \"%s\" error: verticesV (%d elements) and verticesA (%d elements) must have the same lengths.\n",
               this->getParent()->parameters()->groupKeywordFromName(this->getName()),
               this->getName(),
               numVertices, numVerticesA);
      }
      MPI_Barrier(this->getParent()->icCommunicator()->communicator());
      exit(EXIT_FAILURE);
   }
   assert(numVertices==0 || numVertices==numVerticesA);
   numVertices = numVerticesA;
}

void PtwiseLinearTransferLayer::ioParam_slopeNegInf(enum ParamsIOFlag ioFlag) {
   parent->ioParamValue(ioFlag, name, "slopeNegInf", &slopeNegInf, slopeNegInf/*default*/, true/*warnIfAbsent*/);
}

void PtwiseLinearTransferLayer::ioParam_slopePosInf(enum ParamsIOFlag ioFlag) {
   parent->ioParamValue(ioFlag, name, "slopePosInf", &slopePosInf, slopePosInf/*default*/, true/*warnIfAbsent*/);
}

void PtwiseLinearTransferLayer::ioParam_clearGSynInterval(enum ParamsIOFlag ioFlag) {
   parent->ioParamValue(ioFlag, name, "clearGSynInterval", &clearGSynInterval, 0.0);
   if (ioFlag==PARAMS_IO_READ) {
      nextGSynClearTime = parent->getStartTime();
   }
}

//#ifdef PV_USE_OPENCL
///**
// * Initialize OpenCL buffers.  This must be called after PVLayer data have
// * been allocated.
// */
//int PtwiseLinearTransferLayer::allocateThreadBuffers(const char * kernel_name)
//{
//   int status = HyPerLayer::allocateThreadBuffers(kernel_name);
//
//   //right now there are no PtwiseLinearTransferLayer-specific buffers...
//   return status;
//}
//
//int PtwiseLinearTransferLayer::initializeThreadKernels(const char * kernel_name)
//{
//   char kernelPath[256];
//   char kernelFlags[256];
//
//   int status = CL_SUCCESS;
//   CLDevice * device = parent->getCLDevice();
//
//   const char * pvRelPath = "../PetaVision";
//   sprintf(kernelPath, "%s/%s/src/kernels/%s.cl", parent->getSrcPath(), pvRelPath, kernel_name);
//   sprintf(kernelFlags, "-D PV_USE_OPENCL -cl-fast-relaxed-math -I %s/%s/src/kernels/", parent->getSrcPath(), pvRelPath);
//
//   // create kernels
//   //
//   krUpdate = device->createKernel(kernelPath, kernel_name, kernelFlags);
////kernel name should already be set correctly!
////   if (spikingFlag) {
////      krUpdate = device->createKernel(kernelPath, kernel_name, kernelFlags);
////   }
////   else {
////      krUpdate = device->createKernel(kernelPath, "Retina_nonspiking_update_state", kernelFlags);
////   }
//
//   int argid = 0;
//
//   status |= krUpdate->setKernelArg(argid++, getNumNeurons());
//   status |= krUpdate->setKernelArg(argid++, clayer->loc.nx);
//   status |= krUpdate->setKernelArg(argid++, clayer->loc.ny);
//   status |= krUpdate->setKernelArg(argid++, clayer->loc.nf);
//   status |= krUpdate->setKernelArg(argid++, clayer->loc.nb);
//
//
//   status |= krUpdate->setKernelArg(argid++, clV);
//   status |= krUpdate->setKernelArg(argid++, VThresh);
//   status |= krUpdate->setKernelArg(argid++, AMax);
//   status |= krUpdate->setKernelArg(argid++, AMin);
//   status |= krUpdate->setKernelArg(argid++, AShift);
//   status |= krUpdate->setKernelArg(argid++, getChannelCLBuffer());
////   status |= krUpdate->setKernelArg(argid++, getChannelCLBuffer(CHANNEL_EXC));
////   status |= krUpdate->setKernelArg(argid++, getChannelCLBuffer(CHANNEL_INH));
//   status |= krUpdate->setKernelArg(argid++, clActivity);
//
//   return status;
//}
//int PtwiseLinearTransferLayer::updateStateOpenCL(double time, double dt)
//{
//   int status = CL_SUCCESS;
//
//   // wait for memory to be copied to device
//   if (numWait > 0) {
//       status |= clWaitForEvents(numWait, evList);
//   }
//   for (int i = 0; i < numWait; i++) {
//      clReleaseEvent(evList[i]);
//   }
//   numWait = 0;
//
//   status |= krUpdate->run(getNumNeurons(), nxl*nyl, 0, NULL, &evUpdate);
//   krUpdate->finish();
//
//   status |= getChannelCLBuffer()->copyFromDevice(1, &evUpdate, &evList[getEVGSyn()]);
//   status |= clActivity->copyFromDevice(1, &evUpdate, &evList[getEVActivity()]);
//   numWait += 2; //3;
//
//
//   return status;
//}
//#endif

int PtwiseLinearTransferLayer::checkVertices() {
   assert(numVertices>0);
   int status = PV_SUCCESS;
   for (int v=1; v<numVertices; v++) {
      if (verticesV[v] < verticesV[v-1]) {
         status = PV_FAILURE;
         if (this->getParent()->columnId()==0) {
            fprintf(stderr, "%s \"%s\" error: vertices %d and %d: V-coordinates decrease from %f to %f.\n",
                  this->getParent()->parameters()->groupKeywordFromName(this->getName()),
                  this->getName(), v, v+1, verticesV[v-1], verticesV[v]);
         }
      }
   }
   return status;
}

int PtwiseLinearTransferLayer::setSlopes() {
   assert(numVertices>0);
   assert(verticesA!=NULL);
   assert(verticesV!=NULL);
   slopes = (float *) malloc((size_t)(numVertices+1)*sizeof(*slopes));
   if (slopes == NULL) {
      fprintf(stderr, "%s \"%s\" error: unable to allocate memory for transfer function slopes: %s\n",
            parent->parameters()->groupKeywordFromName(name), name, strerror(errno));
      exit(EXIT_FAILURE);

   }
   slopes[0] = slopeNegInf;
   slopes[numVertices] = slopePosInf;
   for (int k=1; k<numVertices; k++) {
      float V1 = verticesV[k-1];
      float V2 = verticesV[k];
      if (V1!=V2) {
         slopes[k] = (verticesA[k]-verticesA[k-1])/(V2-V1);
      }
      else {
         slopes[k] = verticesA[k]>verticesA[k-1] ? std::numeric_limits<float>::infinity() :
                     verticesA[k]<verticesA[k-1] ? -std::numeric_limits<float>::infinity() :
                     std::numeric_limits<float>::quiet_NaN();
      }
   }
   return PV_SUCCESS;
}

int PtwiseLinearTransferLayer::resetGSynBuffers(double timef, double dt) {
   int status = PV_SUCCESS;
   if (GSyn == NULL) return PV_SUCCESS;
   bool clearNow = clearGSynInterval <= 0 || timef >= nextGSynClearTime;
   if (clearNow) {
      resetGSynBuffers_HyPerLayer(parent->getNBatch(), this->getNumNeurons(), getNumChannels(), GSyn[0]);
   }
   if (clearNow > 0) {
      nextGSynClearTime += clearGSynInterval;
   }
   return status;
}

//! PtwiseLinearTransferLayer update state function, to add support for GPU kernel.
//
/*!
 * REMARKS:
 *      - The kernel calls PtwiseLinearTransferLayer_update_state in
 *        updateStateFunctions.h, which calls
 *        applyGSyn_HyPerLayer (sets V = GSynExc - GSynInh)
 *        setActivity_PtwiseLinearTransferLayer (computes A from V)
 */
int PtwiseLinearTransferLayer::doUpdateState(double time, double dt, const PVLayerLoc * loc, pvdata_t * A,
      pvdata_t * V, int num_channels, pvdata_t * gSynHead)
{
//#ifdef PV_USE_OPENCL
//   if(gpuAccelerateFlag) {
//      updateStateOpenCL(time, dt);
//   }
//   else {
//#endif
      int nx = loc->nx;
      int ny = loc->ny;
      int nf = loc->nf;
      int num_neurons = nx*ny*nf;
      int nbatch = loc->nbatch;
      PtwiseLinearTransferLayer_update_state(nbatch, num_neurons, nx, ny, nf, loc->halo.lt, loc->halo.rt, loc->halo.dn, loc->halo.up, V, numVertices, verticesV, verticesA, slopes, num_channels, gSynHead, A);

//#ifdef PV_USE_OPENCL
//   }
//#endif

   return PV_SUCCESS;
}

int PtwiseLinearTransferLayer::setActivity() {
   const PVLayerLoc * loc = getLayerLoc();
   int nx = loc->nx;
   int ny = loc->ny;
   int nf = loc->nf;
   int nbatch = loc->nbatch;
   PVHalo const * halo = &loc->halo;
   int num_neurons = nx*ny*nf;
   return setActivity_PtwiseLinearTransferLayer(nbatch, num_neurons, getCLayer()->activity->data, getV(), nx, ny, nf, halo->lt, halo->rt, halo->dn, halo->up, numVertices, verticesV, verticesA, slopes);
}

int PtwiseLinearTransferLayer::checkpointRead(char const * cpDir, double * timeptr) {
   int status = HyPerLayer::checkpointRead(cpDir, timeptr);
   if (status==PV_SUCCESS) {
      status = parent->readScalarFromFile(cpDir, getName(), "nextGSynClearTime", &nextGSynClearTime, parent->simulationTime()-parent->getDeltaTime());
   }
   return status;
}

int PtwiseLinearTransferLayer::checkpointWrite(char const * cpDir) {
   int status = HyPerLayer::checkpointWrite(cpDir);
   if (status==PV_SUCCESS) {
      status = parent->writeScalarToFile(cpDir, getName(), "nextGSynClearTime", nextGSynClearTime);
   }
   return status;
}

}  // end namespace PV

///////////////////////////////////////////////////////
//
// implementation of PtwiseLinearTransferLayer kernels
//

#ifdef __cplusplus
extern "C" {
#endif

#ifndef PV_USE_OPENCL
#  include "../kernels/PtwiseLinearTransferLayer_update_state.cl"
#else
#  undef PV_USE_OPENCL
#  include "../kernels/PtwiseLinearTransferLayer_update_state.cl"
#  define PV_USE_OPENCL
#endif

#ifdef __cplusplus
}
#endif

<commit_msg>Bugfixes to PtwiseLinearTransferLayer<commit_after>/*
 * PtwiseLinearTransferLayer.cpp
 *
 *  Created on: July 24, 2015
 *      Author: pschultz
 */

#include "PtwiseLinearTransferLayer.hpp"
#include "updateStateFunctions.h"
#include <limits>

#ifdef __cplusplus
extern "C" {
#endif

void PtwiseLinearTransferLayer_update_state(
    const int nbatch,
    const int numNeurons,
    const int nx,
    const int ny,
    const int nf,
    const int lt,
    const int rt,
    const int dn,
    const int up,

    float * V,
    int numVertices,
    float * verticesV,
    float * verticesA,
    float * slopes,
    int num_channels,
    float * GSynHead,
    float * activity);

#ifdef __cplusplus
}
#endif

namespace PV {

PtwiseLinearTransferLayer::PtwiseLinearTransferLayer() {
   initialize_base();
}

PtwiseLinearTransferLayer::PtwiseLinearTransferLayer(const char * name, HyPerCol * hc) {
   initialize_base();
   initialize(name, hc);
//#ifdef PV_USE_OPENCL
//   if(gpuAccelerateFlag)
//      initializeGPU();
//#endif
}  // end PtwiseLinearTransferLayer::PtwiseLinearTransferLayer(const char *, HyPerCol *)

PtwiseLinearTransferLayer::~PtwiseLinearTransferLayer() {
   free(verticesV); verticesV = NULL;
   free(verticesA); verticesA = NULL;
   free(slopes); slopes = NULL;
}

int PtwiseLinearTransferLayer::initialize_base() {
   numVertices = 0;
   verticesV = NULL;
   verticesA = NULL;
   slopes = NULL;
   slopeNegInf = 1.0f;
   slopePosInf = 1.0f;
   return PV_SUCCESS;
}

int PtwiseLinearTransferLayer::initialize(const char * name, HyPerCol * hc) {
   int status = HyPerLayer::initialize(name, hc);
   assert(status == PV_SUCCESS);

   status |= checkVertices();
   status |= setSlopes();
//#ifdef PV_USE_OPENCL
//   numEvents=NUM_ANN_EVENTS;
//#endif
   return status;
}

int PtwiseLinearTransferLayer::ioParamsFillGroup(enum ParamsIOFlag ioFlag) {
   int status = HyPerLayer::ioParamsFillGroup(ioFlag);

   if (ioFlag==PARAMS_IO_READ) { assert(numVertices==0); }
   ioParam_verticesV(ioFlag);
   ioParam_verticesA(ioFlag);
   assert(numVertices!=0);

   ioParam_slopeNegInf(ioFlag);
   ioParam_slopePosInf(ioFlag);

   ioParam_clearGSynInterval(ioFlag);

   return status;
}

void PtwiseLinearTransferLayer::ioParam_verticesV(enum ParamsIOFlag ioFlag) {
   int numVerticesV;
   this->getParent()->ioParamArray(ioFlag, this->getName(), "verticesV", &verticesV, &numVerticesV);
   if (ioFlag==PARAMS_IO_READ) {
      if (numVerticesV==0) {
         if (this->getParent()->columnId()==0) {
            fprintf(stderr,
                  "%s \"%s\" error: verticesV cannot be empty\n",
                  this->getParent()->parameters()->groupKeywordFromName(this->getName()),
                  this->getName());
         }
         MPI_Barrier(this->getParent()->icCommunicator()->communicator());
         exit(EXIT_FAILURE);
      }
      if (numVertices !=0 && numVerticesV != numVertices) {
         if (this->getParent()->columnId()==0) {
            fprintf(stderr,
                  "%s \"%s\" error: verticesV (%d elements) and verticesA (%d elements) must have the same lengths.\n",
                  this->getParent()->parameters()->groupKeywordFromName(this->getName()),
                  this->getName(),
                  numVerticesV, numVertices);
         }
         MPI_Barrier(this->getParent()->icCommunicator()->communicator());
         exit(EXIT_FAILURE);
      }
      assert(numVertices==0 || numVertices==numVerticesV);
      numVertices = numVerticesV;
   }
}

void PtwiseLinearTransferLayer::ioParam_verticesA(enum ParamsIOFlag ioFlag) {
   int numVerticesA;
   this->getParent()->ioParamArray(ioFlag, this->getName(), "verticesA", &verticesA, &numVerticesA);
   if (ioFlag==PARAMS_IO_READ) {
      if (numVerticesA==0) {
         if (this->getParent()->columnId()==0) {
            fprintf(stderr,
                  "%s \"%s\" error: verticesA cannot be empty\n",
                  this->getParent()->parameters()->groupKeywordFromName(this->getName()),
                  this->getName());
         }
         MPI_Barrier(this->getParent()->icCommunicator()->communicator());
         exit(EXIT_FAILURE);
      }
      if (numVertices !=0 && numVerticesA != numVertices) {
         if (this->getParent()->columnId()==0) {
            fprintf(stderr,
                  "%s \"%s\" error: verticesV (%d elements) and verticesA (%d elements) must have the same lengths.\n",
                  this->getParent()->parameters()->groupKeywordFromName(this->getName()),
                  this->getName(),
                  numVertices, numVerticesA);
         }
         MPI_Barrier(this->getParent()->icCommunicator()->communicator());
         exit(EXIT_FAILURE);
      }
      assert(numVertices==0 || numVertices==numVerticesA);
      numVertices = numVerticesA;
   }
}

void PtwiseLinearTransferLayer::ioParam_slopeNegInf(enum ParamsIOFlag ioFlag) {
   parent->ioParamValue(ioFlag, name, "slopeNegInf", &slopeNegInf, slopeNegInf/*default*/, true/*warnIfAbsent*/);
}

void PtwiseLinearTransferLayer::ioParam_slopePosInf(enum ParamsIOFlag ioFlag) {
   parent->ioParamValue(ioFlag, name, "slopePosInf", &slopePosInf, slopePosInf/*default*/, true/*warnIfAbsent*/);
}

void PtwiseLinearTransferLayer::ioParam_clearGSynInterval(enum ParamsIOFlag ioFlag) {
   parent->ioParamValue(ioFlag, name, "clearGSynInterval", &clearGSynInterval, 0.0);
   if (ioFlag==PARAMS_IO_READ) {
      nextGSynClearTime = parent->getStartTime();
   }
}

//#ifdef PV_USE_OPENCL
///**
// * Initialize OpenCL buffers.  This must be called after PVLayer data have
// * been allocated.
// */
//int PtwiseLinearTransferLayer::allocateThreadBuffers(const char * kernel_name)
//{
//   int status = HyPerLayer::allocateThreadBuffers(kernel_name);
//
//   //right now there are no PtwiseLinearTransferLayer-specific buffers...
//   return status;
//}
//
//int PtwiseLinearTransferLayer::initializeThreadKernels(const char * kernel_name)
//{
//   char kernelPath[256];
//   char kernelFlags[256];
//
//   int status = CL_SUCCESS;
//   CLDevice * device = parent->getCLDevice();
//
//   const char * pvRelPath = "../PetaVision";
//   sprintf(kernelPath, "%s/%s/src/kernels/%s.cl", parent->getSrcPath(), pvRelPath, kernel_name);
//   sprintf(kernelFlags, "-D PV_USE_OPENCL -cl-fast-relaxed-math -I %s/%s/src/kernels/", parent->getSrcPath(), pvRelPath);
//
//   // create kernels
//   //
//   krUpdate = device->createKernel(kernelPath, kernel_name, kernelFlags);
////kernel name should already be set correctly!
////   if (spikingFlag) {
////      krUpdate = device->createKernel(kernelPath, kernel_name, kernelFlags);
////   }
////   else {
////      krUpdate = device->createKernel(kernelPath, "Retina_nonspiking_update_state", kernelFlags);
////   }
//
//   int argid = 0;
//
//   status |= krUpdate->setKernelArg(argid++, getNumNeurons());
//   status |= krUpdate->setKernelArg(argid++, clayer->loc.nx);
//   status |= krUpdate->setKernelArg(argid++, clayer->loc.ny);
//   status |= krUpdate->setKernelArg(argid++, clayer->loc.nf);
//   status |= krUpdate->setKernelArg(argid++, clayer->loc.nb);
//
//
//   status |= krUpdate->setKernelArg(argid++, clV);
//   status |= krUpdate->setKernelArg(argid++, VThresh);
//   status |= krUpdate->setKernelArg(argid++, AMax);
//   status |= krUpdate->setKernelArg(argid++, AMin);
//   status |= krUpdate->setKernelArg(argid++, AShift);
//   status |= krUpdate->setKernelArg(argid++, getChannelCLBuffer());
////   status |= krUpdate->setKernelArg(argid++, getChannelCLBuffer(CHANNEL_EXC));
////   status |= krUpdate->setKernelArg(argid++, getChannelCLBuffer(CHANNEL_INH));
//   status |= krUpdate->setKernelArg(argid++, clActivity);
//
//   return status;
//}
//int PtwiseLinearTransferLayer::updateStateOpenCL(double time, double dt)
//{
//   int status = CL_SUCCESS;
//
//   // wait for memory to be copied to device
//   if (numWait > 0) {
//       status |= clWaitForEvents(numWait, evList);
//   }
//   for (int i = 0; i < numWait; i++) {
//      clReleaseEvent(evList[i]);
//   }
//   numWait = 0;
//
//   status |= krUpdate->run(getNumNeurons(), nxl*nyl, 0, NULL, &evUpdate);
//   krUpdate->finish();
//
//   status |= getChannelCLBuffer()->copyFromDevice(1, &evUpdate, &evList[getEVGSyn()]);
//   status |= clActivity->copyFromDevice(1, &evUpdate, &evList[getEVActivity()]);
//   numWait += 2; //3;
//
//
//   return status;
//}
//#endif

int PtwiseLinearTransferLayer::checkVertices() {
   assert(numVertices>0);
   int status = PV_SUCCESS;
   for (int v=1; v<numVertices; v++) {
      if (verticesV[v] < verticesV[v-1]) {
         status = PV_FAILURE;
         if (this->getParent()->columnId()==0) {
            fprintf(stderr, "%s \"%s\" error: vertices %d and %d: V-coordinates decrease from %f to %f.\n",
                  this->getParent()->parameters()->groupKeywordFromName(this->getName()),
                  this->getName(), v, v+1, verticesV[v-1], verticesV[v]);
         }
      }
   }
   return status;
}

int PtwiseLinearTransferLayer::setSlopes() {
   assert(numVertices>0);
   assert(verticesA!=NULL);
   assert(verticesV!=NULL);
   slopes = (float *) malloc((size_t)(numVertices+1)*sizeof(*slopes));
   if (slopes == NULL) {
      fprintf(stderr, "%s \"%s\" error: unable to allocate memory for transfer function slopes: %s\n",
            parent->parameters()->groupKeywordFromName(name), name, strerror(errno));
      exit(EXIT_FAILURE);

   }
   slopes[0] = slopeNegInf;
   slopes[numVertices] = slopePosInf;
   for (int k=1; k<numVertices; k++) {
      float V1 = verticesV[k-1];
      float V2 = verticesV[k];
      if (V1!=V2) {
         slopes[k] = (verticesA[k]-verticesA[k-1])/(V2-V1);
      }
      else {
         slopes[k] = verticesA[k]>verticesA[k-1] ? std::numeric_limits<float>::infinity() :
                     verticesA[k]<verticesA[k-1] ? -std::numeric_limits<float>::infinity() :
                     std::numeric_limits<float>::quiet_NaN();
      }
   }
   return PV_SUCCESS;
}

int PtwiseLinearTransferLayer::resetGSynBuffers(double timef, double dt) {
   int status = PV_SUCCESS;
   if (GSyn == NULL) return PV_SUCCESS;
   bool clearNow = clearGSynInterval <= 0 || timef >= nextGSynClearTime;
   if (clearNow) {
      resetGSynBuffers_HyPerLayer(parent->getNBatch(), this->getNumNeurons(), getNumChannels(), GSyn[0]);
   }
   if (clearNow > 0) {
      nextGSynClearTime += clearGSynInterval;
   }
   return status;
}

//! PtwiseLinearTransferLayer update state function, to add support for GPU kernel.
//
/*!
 * REMARKS:
 *      - The kernel calls PtwiseLinearTransferLayer_update_state in
 *        updateStateFunctions.h, which calls
 *        applyGSyn_HyPerLayer (sets V = GSynExc - GSynInh)
 *        setActivity_PtwiseLinearTransferLayer (computes A from V)
 */
int PtwiseLinearTransferLayer::doUpdateState(double time, double dt, const PVLayerLoc * loc, pvdata_t * A,
      pvdata_t * V, int num_channels, pvdata_t * gSynHead)
{
//#ifdef PV_USE_OPENCL
//   if(gpuAccelerateFlag) {
//      updateStateOpenCL(time, dt);
//   }
//   else {
//#endif
      int nx = loc->nx;
      int ny = loc->ny;
      int nf = loc->nf;
      int num_neurons = nx*ny*nf;
      int nbatch = loc->nbatch;
      PtwiseLinearTransferLayer_update_state(nbatch, num_neurons, nx, ny, nf, loc->halo.lt, loc->halo.rt, loc->halo.dn, loc->halo.up, V, numVertices, verticesV, verticesA, slopes, num_channels, gSynHead, A);

//#ifdef PV_USE_OPENCL
//   }
//#endif

   return PV_SUCCESS;
}

int PtwiseLinearTransferLayer::setActivity() {
   const PVLayerLoc * loc = getLayerLoc();
   int nx = loc->nx;
   int ny = loc->ny;
   int nf = loc->nf;
   int nbatch = loc->nbatch;
   PVHalo const * halo = &loc->halo;
   int num_neurons = nx*ny*nf;
   return setActivity_PtwiseLinearTransferLayer(nbatch, num_neurons, getCLayer()->activity->data, getV(), nx, ny, nf, halo->lt, halo->rt, halo->dn, halo->up, numVertices, verticesV, verticesA, slopes);
}

int PtwiseLinearTransferLayer::checkpointRead(char const * cpDir, double * timeptr) {
   int status = HyPerLayer::checkpointRead(cpDir, timeptr);
   if (status==PV_SUCCESS) {
      status = parent->readScalarFromFile(cpDir, getName(), "nextGSynClearTime", &nextGSynClearTime, parent->simulationTime()-parent->getDeltaTime());
   }
   return status;
}

int PtwiseLinearTransferLayer::checkpointWrite(char const * cpDir) {
   int status = HyPerLayer::checkpointWrite(cpDir);
   if (status==PV_SUCCESS) {
      status = parent->writeScalarToFile(cpDir, getName(), "nextGSynClearTime", nextGSynClearTime);
   }
   return status;
}

}  // end namespace PV

///////////////////////////////////////////////////////
//
// implementation of PtwiseLinearTransferLayer kernels
//

#ifdef __cplusplus
extern "C" {
#endif

#ifndef PV_USE_OPENCL
#  include "../kernels/PtwiseLinearTransferLayer_update_state.cl"
#else
#  undef PV_USE_OPENCL
#  include "../kernels/PtwiseLinearTransferLayer_update_state.cl"
#  define PV_USE_OPENCL
#endif

#ifdef __cplusplus
}
#endif

<|endoftext|>


<commit_before><commit_msg>don't leak memory when getting token responses<commit_after><|endoftext|>


<commit_before>/*=============================================================================
	Copyright (c) 2012-2014 Richard Otis

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/

// definition for GibbsOpt constructor and destructor

#include "libgibbs/include/libgibbs_pch.hpp"
#include "libgibbs/include/models.hpp"
#include "libgibbs/include/utils/math_expr.hpp"
#include "libgibbs/include/optimizer/opt_Gibbs.hpp"
#include "libgibbs/include/optimizer/utils/build_variable_map.hpp"
#include "libgibbs/include/optimizer/utils/ezd_minimization.hpp"
#include "libtdb/include/logging.hpp"
#include <sstream>

using namespace Optimizer;

// Add new_tree to root_tree
void add_trees (boost::spirit::utree &root_tree, const boost::spirit::utree &new_tree) {
	boost::spirit::utree temp_tree;
	temp_tree.push_back("+");
	temp_tree.push_back(root_tree);
	temp_tree.push_back(new_tree);
	root_tree.swap(temp_tree);
}

GibbsOpt::GibbsOpt(
		const Database &DB,
		const evalconditions &sysstate) :
			conditions(sysstate),
			phase_iter(DB.get_phase_iterator()),
			phase_end(DB.get_phase_iterator_end())
{
	BOOST_LOG_NAMED_SCOPE("GibbsOpt::GibbsOpt");
	BOOST_LOG_CHANNEL_SEV(opto_log, "optimizer", debug) << "enter ctor";
	int varcount = 0;
	int activephases = 0;
	parameter_set pset;

	for (auto i = DB.get_phase_iterator(); i != DB.get_phase_iterator_end(); ++i) {
		if (conditions.phases.find(i->first) != conditions.phases.end()) {
			if (conditions.phases.at(i->first) == PhaseStatus::ENTERED) {
				phase_col[i->first] = i->second;
			}
		}
	}

	phase_iter = phase_col.cbegin();
	phase_end = phase_col.cend();
	if (conditions.elements.cbegin() == conditions.elements.cend()) BOOST_LOG_SEV(opto_log, critical) << "No components entered!";
	if (phase_iter == phase_end) BOOST_LOG_SEV(opto_log, critical) << "No phases found!";

	// build_variable_map() will fill main_indices by reference
	// main_indices is used during the optimization as a simplified variable map
	main_ss = build_variable_map(phase_iter, phase_end, conditions, main_indices);

	for (auto i = main_indices.left.begin(); i != main_indices.left.end(); ++i) {
		BOOST_LOG_SEV(opto_log, debug) << "Variable " << i->second << ": " << i->first;
	}

	// load the parameters from the database
	pset = DB.get_parameter_set();

	// this is the part where we look up the models enabled for each phase and call their AST builders
	// then we build a master Gibbs AST for the objective function
	for (auto i = phase_iter; i != phase_end; ++i) {
		if (conditions.phases[i->first] != PhaseStatus::ENTERED) continue;
		++activephases;
                CompositionSet main_compset = CompositionSet(i->second, pset, main_ss, main_indices);
		std::vector<std::map<std::string,double>> minima = Optimizer::LocateMinima(main_compset, main_ss, conditions);
                BOOST_LOG_SEV(opto_log, debug) << minima.size() << " minima detected from global minimization";
                if (minima.size() == 1) {
                    // No miscibility gap, no need to create new composition sets
                    // Use the minimum found during global minimization as the starting point
                    main_compset.set_starting_point(*(minima.begin()));
                    comp_sets.emplace(main_compset.name(), std::move(main_compset));
                }
                if (minima.size() > 1) {
                    // Miscibility gap detected; create a new composition set for each minimum
                    std::size_t compsetcount = 1;
                    std::map<std::string, CompositionSet>::iterator it;
                    for (auto min = minima.begin(); min != minima.end(); ++min) {
                        if (min == minima.begin()) {
                            // For the first one, don't clone it; just rename it
                            std::stringstream compsetname;
                            compsetname << main_compset.name() << "#" << compsetcount;

                            // Set starting point
                            main_compset.set_starting_point(*(min));
                            // Rename from PHASENAME to PHASENAME#1
                            it = comp_sets.emplace(compsetname.str(), std::move(main_compset)).first;
                        }
                        else {
                            ++compsetcount;
                            ++activephases;
                            std::stringstream compsetname;
                            compsetname << it->second.name() << "#" << compsetcount;
                            // Use special constructor which copies, renames and sets the start point
                            comp_sets.emplace(compsetname.str(), CompositionSet(it->second, *min, compsetname.str()));
                            BOOST_LOG_SEV(opto_log, debug) << "Created composition set " << compsetname.str();
                        }
                    }
                }
        }

	// Add the mandatory constraints to the ConstraintManager
	if (activephases > 1)
		cm.addConstraint(
				PhaseFractionBalanceConstraint(
						phase_iter, phase_end
					)
				); // Add the mass balance constraint to ConstraintManager (mandatory)
	if (activephases == 1) {
		// If only one phase is present, fix its corresponding variable index
		std::stringstream ss;
		ss << (phase_col.begin())->first << "_FRAC";
		fixed_indices.push_back(main_indices.left.at(ss.str()));
	}

	// Add the sublattice site fraction constraints (mandatory)
	for (auto i = phase_iter; i != phase_end; ++i) {
		if (conditions.phases[i->first] != PhaseStatus::ENTERED) continue;
		for (auto j = i->second.get_sublattice_iterator(); j != i->second.get_sublattice_iterator_end();++j) {
			std::vector<std::string> subl_list;
			for (auto k = (*j).get_species_iterator(); k != (*j).get_species_iterator_end();++k) {
				// Check if this species in this sublattice is on our list of elements to investigate
				if (std::find(conditions.elements.cbegin(),conditions.elements.cend(),*k) != conditions.elements.cend()) {
					subl_list.push_back(*k); // Add to the list
				}
			}
			if (subl_list.size() == 1) {
				std::stringstream ss;
				ss << i->first << "_" << std::distance(i->second.get_sublattice_iterator(),j) << "_" << *(subl_list.begin());
				fixed_indices.push_back(main_indices.left.at(ss.str()));
			}
			if (subl_list.size() > 1 ) {
				cm.addConstraint(
						SublatticeBalanceConstraint(
								i->first,
								std::distance(i->second.get_sublattice_iterator(),j),
								subl_list.cbegin(),
								subl_list.cend()
						)
				);
			}
		}
	}

	// Add any user-specified constraints to the ConstraintManager

	for (auto i = conditions.xfrac.cbegin(); i != conditions.xfrac.cend(); ++i) {
		cm.addConstraint(MassBalanceConstraint(phase_iter, phase_end, i->first, i->second));
	}

	for (auto i = cm.constraints.begin() ; i != cm.constraints.end(); ++i) {
		BOOST_LOG_SEV(opto_log, debug) << "Constraint " << i->name << " LHS: " << i->lhs;
		BOOST_LOG_SEV(opto_log, debug) << "Constraint " << i->name << " RHS: " << i->rhs;
	}

	// Calculate first derivative ASTs of all constraints
	for (auto i = main_indices.left.begin(); i != main_indices.left.end(); ++i) {
		// for each variable, calculate derivatives of all the constraints
		for (auto j = cm.constraints.begin(); j != cm.constraints.end(); ++j) {
			boost::spirit::utree lhs = differentiate_utree(j->lhs, i->first);
			boost::spirit::utree rhs = differentiate_utree(j->rhs, i->first);
			lhs = simplify_utree(lhs);
			rhs = simplify_utree(rhs);
			if (
					(lhs.which() == boost::spirit::utree_type::double_type || lhs.which() == boost::spirit::utree_type::int_type)
					&&
					(rhs.which() == boost::spirit::utree_type::double_type || rhs.which() == boost::spirit::utree_type::int_type)
			)
			{
				double lhsget, rhsget;
				lhsget = lhs.get<double>();
				rhsget = rhs.get<double>();
				if (lhsget == rhsget) continue; // don't add zeros to the Jacobian
			}
			boost::spirit::utree subtract_tree;
			subtract_tree.push_back("-");
			subtract_tree.push_back(lhs);
			subtract_tree.push_back(rhs);
			int var_index = i->second;
			int cons_index = std::distance(cm.constraints.begin(),j);
			jac_g_trees.push_back(jacobian_entry(cons_index,var_index,false,subtract_tree));
			BOOST_LOG_SEV(opto_log, debug) << "Jacobian of constraint  " << cons_index << " wrt variable " << var_index << " pre-calculated";
		}
	}

	// Add nonzero elements from objective Hessian to sparsity structure
	for (auto i = comp_sets.cbegin(); i != comp_sets.cend(); ++i) {
		std::set<std::list<int>> comp_set_hess_sparsity_structure = i->second.hessian_sparsity_structure(main_indices);
		for (auto j = comp_set_hess_sparsity_structure.cbegin(); j != comp_set_hess_sparsity_structure.cend(); ++j) {
			hess_sparsity_structure.insert(*j);
		}
	}

	// Calculate second derivatives of constraints
	for (auto i = main_indices.left.begin(); i != main_indices.left.end(); ++i) {
		// for each variable, calculate derivatives of the Jacobian w.r.t all the constraints
		for (auto j = jac_g_trees.cbegin(); j != jac_g_trees.cend(); ++j) {
			if (i->second > j->var_index) continue; // skip upper triangular
			// second derivative of constraint jac_g_trees->cons_index w.r.t jac_g_trees->var_index, i->second
			boost::spirit::utree cons_second_deriv = differentiate_utree(j->ast, i->first);
			//cons_second_deriv = simplify_utree(cons_second_deriv);
			hessian_set::iterator h_iter, h_end;
			// don't add zeros to the Hessian
			if (is_zero_tree(cons_second_deriv)) continue;

			h_iter = constraint_hessian_data.lower_bound(boost::make_tuple(i->second,j->var_index));
			h_end = constraint_hessian_data.upper_bound(boost::make_tuple(i->second,j->var_index));
			// create a new Hessian record if it does not exist
			if (h_iter == h_end) h_iter = constraint_hessian_data.insert(hessian_entry(i->second,j->var_index)).first;
			hessian_entry h_entry = *h_iter;
			h_entry.asts[j->cons_index] = cons_second_deriv; // set AST for constraint Hessian
			constraint_hessian_data.replace(h_iter, h_entry); // update original entry
			const std::list<int> nonzerolist {i->second, j->var_index};
			hess_sparsity_structure.insert(nonzerolist); // add nonzero to sparsity structure
			BOOST_LOG_SEV(opto_log, debug) << "Hessian of constraint  "
					<< j->cons_index << " (" << i->second << "," << j->var_index << ") pre-calculated";
		}
	}

	BOOST_LOG_SEV(opto_log, debug) << "function exit";
}

GibbsOpt::~GibbsOpt()
{}
<commit_msg>Fix formatting<commit_after>/*=============================================================================
	Copyright (c) 2012-2014 Richard Otis

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/

// definition for GibbsOpt constructor and destructor

#include "libgibbs/include/libgibbs_pch.hpp"
#include "libgibbs/include/models.hpp"
#include "libgibbs/include/utils/math_expr.hpp"
#include "libgibbs/include/optimizer/opt_Gibbs.hpp"
#include "libgibbs/include/optimizer/utils/build_variable_map.hpp"
#include "libgibbs/include/optimizer/utils/ezd_minimization.hpp"
#include "libtdb/include/logging.hpp"
#include <sstream>

using namespace Optimizer;

// Add new_tree to root_tree
void add_trees ( boost::spirit::utree &root_tree, const boost::spirit::utree &new_tree )
    {
    boost::spirit::utree temp_tree;
    temp_tree.push_back ( "+" );
    temp_tree.push_back ( root_tree );
    temp_tree.push_back ( new_tree );
    root_tree.swap ( temp_tree );
    }

GibbsOpt::GibbsOpt (
    const Database &DB,
    const evalconditions &sysstate ) :
    conditions ( sysstate ),
    phase_iter ( DB.get_phase_iterator() ),
    phase_end ( DB.get_phase_iterator_end() )
    {
    BOOST_LOG_NAMED_SCOPE ( "GibbsOpt::GibbsOpt" );
    BOOST_LOG_CHANNEL_SEV ( opto_log, "optimizer", debug ) << "enter ctor";
    int varcount = 0;
    int activephases = 0;
    parameter_set pset;

    for ( auto i = DB.get_phase_iterator(); i != DB.get_phase_iterator_end(); ++i )
        {
        if ( conditions.phases.find ( i->first ) != conditions.phases.end() )
            {
            if ( conditions.phases.at ( i->first ) == PhaseStatus::ENTERED )
                {
                phase_col[i->first] = i->second;
                }
            }
        }

    phase_iter = phase_col.cbegin();
    phase_end = phase_col.cend();
    if ( conditions.elements.cbegin() == conditions.elements.cend() ) BOOST_LOG_SEV ( opto_log, critical ) << "No components entered!";
    if ( phase_iter == phase_end ) BOOST_LOG_SEV ( opto_log, critical ) << "No phases found!";

    // build_variable_map() will fill main_indices by reference
    // main_indices is used during the optimization as a simplified variable map
    main_ss = build_variable_map ( phase_iter, phase_end, conditions, main_indices );

    for ( auto i = main_indices.left.begin(); i != main_indices.left.end(); ++i )
        {
        BOOST_LOG_SEV ( opto_log, debug ) << "Variable " << i->second << ": " << i->first;
        }

    // load the parameters from the database
    pset = DB.get_parameter_set();

    // this is the part where we look up the models enabled for each phase and call their AST builders
    // then we build a master Gibbs AST for the objective function
    for ( auto i = phase_iter; i != phase_end; ++i )
        {
        if ( conditions.phases[i->first] != PhaseStatus::ENTERED ) continue;
        ++activephases;
        CompositionSet main_compset = CompositionSet ( i->second, pset, main_ss, main_indices );
        std::vector<std::map<std::string,double>> minima = Optimizer::LocateMinima ( main_compset, main_ss, conditions );
        BOOST_LOG_SEV ( opto_log, debug ) << minima.size() << " minima detected from global minimization";
        if ( minima.size() == 1 )
            {
            // No miscibility gap, no need to create new composition sets
            // Use the minimum found during global minimization as the starting point
            main_compset.set_starting_point ( * ( minima.begin() ) );
            comp_sets.emplace ( main_compset.name(), std::move ( main_compset ) );
            }
        if ( minima.size() > 1 )
            {
            // Miscibility gap detected; create a new composition set for each minimum
            std::size_t compsetcount = 1;
            std::map<std::string, CompositionSet>::iterator it;
            for ( auto min = minima.begin(); min != minima.end(); ++min )
                {
                if ( min == minima.begin() )
                    {
                    // For the first one, don't clone it; just rename it
                    std::stringstream compsetname;
                    compsetname << main_compset.name() << "#" << compsetcount;

                    // Set starting point
                    main_compset.set_starting_point ( * ( min ) );
                    // Rename from PHASENAME to PHASENAME#1
                    it = comp_sets.emplace ( compsetname.str(), std::move ( main_compset ) ).first;
                    }
                else
                    {
                    ++compsetcount;
                    ++activephases;
                    std::stringstream compsetname;
                    compsetname << it->second.name() << "#" << compsetcount;
                    // Use special constructor which copies, renames and sets the start point
                    comp_sets.emplace ( compsetname.str(), CompositionSet ( it->second, *min, compsetname.str() ) );
                    BOOST_LOG_SEV ( opto_log, debug ) << "Created composition set " << compsetname.str();
                    }
                }
            }
        }

    // Add the mandatory constraints to the ConstraintManager
    if ( activephases > 1 )
        cm.addConstraint (
            PhaseFractionBalanceConstraint (
                phase_iter, phase_end
            )
        ); // Add the mass balance constraint to ConstraintManager (mandatory)
    if ( activephases == 1 )
        {
        // If only one phase is present, fix its corresponding variable index
        std::stringstream ss;
        ss << ( phase_col.begin() )->first << "_FRAC";
        fixed_indices.push_back ( main_indices.left.at ( ss.str() ) );
        }

    // Add the sublattice site fraction constraints (mandatory)
    for ( auto i = phase_iter; i != phase_end; ++i )
        {
        if ( conditions.phases[i->first] != PhaseStatus::ENTERED ) continue;
        for ( auto j = i->second.get_sublattice_iterator(); j != i->second.get_sublattice_iterator_end(); ++j )
            {
            std::vector<std::string> subl_list;
            for ( auto k = ( *j ).get_species_iterator(); k != ( *j ).get_species_iterator_end(); ++k )
                {
                // Check if this species in this sublattice is on our list of elements to investigate
                if ( std::find ( conditions.elements.cbegin(),conditions.elements.cend(),*k ) != conditions.elements.cend() )
                    {
                    subl_list.push_back ( *k ); // Add to the list
                    }
                }
            if ( subl_list.size() == 1 )
                {
                std::stringstream ss;
                ss << i->first << "_" << std::distance ( i->second.get_sublattice_iterator(),j ) << "_" << * ( subl_list.begin() );
                fixed_indices.push_back ( main_indices.left.at ( ss.str() ) );
                }
            if ( subl_list.size() > 1 )
                {
                cm.addConstraint (
                    SublatticeBalanceConstraint (
                        i->first,
                        std::distance ( i->second.get_sublattice_iterator(),j ),
                        subl_list.cbegin(),
                        subl_list.cend()
                    )
                );
                }
            }
        }

    // Add any user-specified constraints to the ConstraintManager

    for ( auto i = conditions.xfrac.cbegin(); i != conditions.xfrac.cend(); ++i )
        {
        cm.addConstraint ( MassBalanceConstraint ( phase_iter, phase_end, i->first, i->second ) );
        }

    for ( auto i = cm.constraints.begin() ; i != cm.constraints.end(); ++i )
        {
        BOOST_LOG_SEV ( opto_log, debug ) << "Constraint " << i->name << " LHS: " << i->lhs;
        BOOST_LOG_SEV ( opto_log, debug ) << "Constraint " << i->name << " RHS: " << i->rhs;
        }

    // Calculate first derivative ASTs of all constraints
    for ( auto i = main_indices.left.begin(); i != main_indices.left.end(); ++i )
        {
        // for each variable, calculate derivatives of all the constraints
        for ( auto j = cm.constraints.begin(); j != cm.constraints.end(); ++j )
            {
            boost::spirit::utree lhs = differentiate_utree ( j->lhs, i->first );
            boost::spirit::utree rhs = differentiate_utree ( j->rhs, i->first );
            lhs = simplify_utree ( lhs );
            rhs = simplify_utree ( rhs );
            if (
                ( lhs.which() == boost::spirit::utree_type::double_type || lhs.which() == boost::spirit::utree_type::int_type )
                &&
                ( rhs.which() == boost::spirit::utree_type::double_type || rhs.which() == boost::spirit::utree_type::int_type )
            )
                {
                double lhsget, rhsget;
                lhsget = lhs.get<double>();
                rhsget = rhs.get<double>();
                if ( lhsget == rhsget ) continue; // don't add zeros to the Jacobian
                }
            boost::spirit::utree subtract_tree;
            subtract_tree.push_back ( "-" );
            subtract_tree.push_back ( lhs );
            subtract_tree.push_back ( rhs );
            int var_index = i->second;
            int cons_index = std::distance ( cm.constraints.begin(),j );
            jac_g_trees.push_back ( jacobian_entry ( cons_index,var_index,false,subtract_tree ) );
            BOOST_LOG_SEV ( opto_log, debug ) << "Jacobian of constraint  " << cons_index << " wrt variable " << var_index << " pre-calculated";
            }
        }

    // Add nonzero elements from objective Hessian to sparsity structure
    for ( auto i = comp_sets.cbegin(); i != comp_sets.cend(); ++i )
        {
        std::set<std::list<int>> comp_set_hess_sparsity_structure = i->second.hessian_sparsity_structure ( main_indices );
        for ( auto j = comp_set_hess_sparsity_structure.cbegin(); j != comp_set_hess_sparsity_structure.cend(); ++j )
            {
            hess_sparsity_structure.insert ( *j );
            }
        }

    // Calculate second derivatives of constraints
    for ( auto i = main_indices.left.begin(); i != main_indices.left.end(); ++i )
        {
        // for each variable, calculate derivatives of the Jacobian w.r.t all the constraints
        for ( auto j = jac_g_trees.cbegin(); j != jac_g_trees.cend(); ++j )
            {
            if ( i->second > j->var_index ) continue; // skip upper triangular
            // second derivative of constraint jac_g_trees->cons_index w.r.t jac_g_trees->var_index, i->second
            boost::spirit::utree cons_second_deriv = differentiate_utree ( j->ast, i->first );
            //cons_second_deriv = simplify_utree(cons_second_deriv);
            hessian_set::iterator h_iter, h_end;
            // don't add zeros to the Hessian
            if ( is_zero_tree ( cons_second_deriv ) ) continue;

            h_iter = constraint_hessian_data.lower_bound ( boost::make_tuple ( i->second,j->var_index ) );
            h_end = constraint_hessian_data.upper_bound ( boost::make_tuple ( i->second,j->var_index ) );
            // create a new Hessian record if it does not exist
            if ( h_iter == h_end ) h_iter = constraint_hessian_data.insert ( hessian_entry ( i->second,j->var_index ) ).first;
            hessian_entry h_entry = *h_iter;
            h_entry.asts[j->cons_index] = cons_second_deriv; // set AST for constraint Hessian
            constraint_hessian_data.replace ( h_iter, h_entry ); // update original entry
            const std::list<int> nonzerolist {i->second, j->var_index};
            hess_sparsity_structure.insert ( nonzerolist ); // add nonzero to sparsity structure
            BOOST_LOG_SEV ( opto_log, debug ) << "Hessian of constraint  "
                                              << j->cons_index << " (" << i->second << "," << j->var_index << ") pre-calculated";
            }
        }

    BOOST_LOG_SEV ( opto_log, debug ) << "function exit";
    }

GibbsOpt::~GibbsOpt()
    {}
// kate: indent-mode cstyle; indent-width 4; replace-tabs on;
<|endoftext|>


<commit_before>/* ************************************************************************
 * Copyright 2018 Advanced Micro Devices, Inc.
 *
 * ************************************************************************ */

#include "rocsparse.h"
#include "rocsparse_csr2ell.hpp"

/*
 * ===========================================================================
 *    C wrapper
 * ===========================================================================
 */

extern "C" rocsparse_status rocsparse_csr2ell_width(rocsparse_handle handle,
                                                    rocsparse_int m,
                                                    const rocsparse_mat_descr csr_descr,
                                                    const rocsparse_int* csr_row_ptr,
                                                    const rocsparse_mat_descr ell_descr,
                                                    rocsparse_int* ell_width)
{
    // Check for valid handle and matrix descriptor
    if(handle == nullptr)
    {
        return rocsparse_status_invalid_handle;
    }
    else if(csr_descr == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }
    else if(ell_descr == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }

    // Logging
    log_trace(handle,
              "rocsparse_csr2ell_width",
              m,
              (const void*&)csr_descr,
              (const void*&)csr_row_ptr,
              (const void*&)ell_descr,
              (const void*&)ell_width);

    // Check index base
    if(csr_descr->base != rocsparse_index_base_zero && csr_descr->base != rocsparse_index_base_one)
    {
        return rocsparse_status_invalid_value;
    }
    if(ell_descr->base != rocsparse_index_base_zero && ell_descr->base != rocsparse_index_base_one)
    {
        return rocsparse_status_invalid_value;
    }
    // Check matrix type
    if(csr_descr->type != rocsparse_matrix_type_general)
    {
        // TODO
        return rocsparse_status_not_implemented;
    }
    if(ell_descr->type != rocsparse_matrix_type_general)
    {
        // TODO
        return rocsparse_status_not_implemented;
    }

    // Check sizes
    if(m < 0)
    {
        return rocsparse_status_invalid_size;
    }

    // Check pointer arguments
    if(csr_row_ptr == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }
    else if(ell_width == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }

    // Quick return if possible
    if(m == 0)
    {
        if(handle->pointer_mode == rocsparse_pointer_mode_device)
        {
            RETURN_IF_HIP_ERROR(hipMemset(ell_width, 0, sizeof(rocsparse_int)));
        }
        else
        {
            *ell_width = 0;
        }
        return rocsparse_status_success;
    }

    hipStream_t stream = handle->stream;

// Determine ELL width

#define CSR2ELL_DIM 512
    // Workspace size
    rocsparse_int blocks = (m - 1) / CSR2ELL_DIM + 1;

    // Allocate workspace
    rocsparse_int* workspace = NULL;
    RETURN_IF_HIP_ERROR(hipMalloc((void**)&workspace, sizeof(rocsparse_int) * blocks));

    // Compute maximum nnz per row
    hipLaunchKernelGGL((ell_width_kernel_part1<CSR2ELL_DIM>),
                       dim3(blocks),
                       dim3(CSR2ELL_DIM),
                       0,
                       stream,
                       m,
                       csr_row_ptr,
                       workspace);

    hipLaunchKernelGGL((ell_width_kernel_part2<CSR2ELL_DIM>),
                       dim3(1),
                       dim3(CSR2ELL_DIM),
                       0,
                       stream,
                       blocks,
                       workspace);

    // Copy ELL width back to host, if handle says so
    if(handle->pointer_mode == rocsparse_pointer_mode_device)
    {
        RETURN_IF_HIP_ERROR(
            hipMemcpy(ell_width, workspace, sizeof(rocsparse_int), hipMemcpyDeviceToDevice));
    }
    else
    {
        RETURN_IF_HIP_ERROR(
            hipMemcpy(ell_width, workspace, sizeof(rocsparse_int), hipMemcpyDeviceToHost));
    }

    return rocsparse_status_success;
}

extern "C" rocsparse_status rocsparse_scsr2ell(rocsparse_handle handle,
                                               rocsparse_int m,
                                               const rocsparse_mat_descr csr_descr,
                                               const float* csr_val,
                                               const rocsparse_int* csr_row_ptr,
                                               const rocsparse_int* csr_col_ind,
                                               const rocsparse_mat_descr ell_descr,
                                               rocsparse_int ell_width,
                                               float* ell_val,
                                               rocsparse_int* ell_col_ind)
{
    return rocsparse_csr2ell_template<float>(handle,
                                             m,
                                             csr_descr,
                                             csr_val,
                                             csr_row_ptr,
                                             csr_col_ind,
                                             ell_descr,
                                             ell_width,
                                             ell_val,
                                             ell_col_ind);
}

extern "C" rocsparse_status rocsparse_dcsr2ell(rocsparse_handle handle,
                                               rocsparse_int m,
                                               const rocsparse_mat_descr csr_descr,
                                               const double* csr_val,
                                               const rocsparse_int* csr_row_ptr,
                                               const rocsparse_int* csr_col_ind,
                                               const rocsparse_mat_descr ell_descr,
                                               rocsparse_int ell_width,
                                               double* ell_val,
                                               rocsparse_int* ell_col_ind)
{
    return rocsparse_csr2ell_template<double>(handle,
                                              m,
                                              csr_descr,
                                              csr_val,
                                              csr_row_ptr,
                                              csr_col_ind,
                                              ell_descr,
                                              ell_width,
                                              ell_val,
                                              ell_col_ind);
}
<commit_msg>mem leak fix in csr2ell and changed to non-blocking<commit_after>/* ************************************************************************
 * Copyright 2018 Advanced Micro Devices, Inc.
 *
 * ************************************************************************ */

#include "rocsparse.h"
#include "rocsparse_csr2ell.hpp"

/*
 * ===========================================================================
 *    C wrapper
 * ===========================================================================
 */

extern "C" rocsparse_status rocsparse_csr2ell_width(rocsparse_handle handle,
                                                    rocsparse_int m,
                                                    const rocsparse_mat_descr csr_descr,
                                                    const rocsparse_int* csr_row_ptr,
                                                    const rocsparse_mat_descr ell_descr,
                                                    rocsparse_int* ell_width)
{
    // Check for valid handle and matrix descriptor
    if(handle == nullptr)
    {
        return rocsparse_status_invalid_handle;
    }
    else if(csr_descr == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }
    else if(ell_descr == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }

    // Logging
    log_trace(handle,
              "rocsparse_csr2ell_width",
              m,
              (const void*&)csr_descr,
              (const void*&)csr_row_ptr,
              (const void*&)ell_descr,
              (const void*&)ell_width);

    // Check index base
    if(csr_descr->base != rocsparse_index_base_zero && csr_descr->base != rocsparse_index_base_one)
    {
        return rocsparse_status_invalid_value;
    }
    if(ell_descr->base != rocsparse_index_base_zero && ell_descr->base != rocsparse_index_base_one)
    {
        return rocsparse_status_invalid_value;
    }
    // Check matrix type
    if(csr_descr->type != rocsparse_matrix_type_general)
    {
        // TODO
        return rocsparse_status_not_implemented;
    }
    if(ell_descr->type != rocsparse_matrix_type_general)
    {
        // TODO
        return rocsparse_status_not_implemented;
    }

    // Check sizes
    if(m < 0)
    {
        return rocsparse_status_invalid_size;
    }

    // Check pointer arguments
    if(csr_row_ptr == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }
    else if(ell_width == nullptr)
    {
        return rocsparse_status_invalid_pointer;
    }

    hipStream_t stream = handle->stream;

    // Quick return if possible
    if(m == 0)
    {
        if(handle->pointer_mode == rocsparse_pointer_mode_device)
        {
            RETURN_IF_HIP_ERROR(hipMemsetAsync(ell_width, 0, sizeof(rocsparse_int), stream));
        }
        else
        {
            *ell_width = 0;
        }
        return rocsparse_status_success;
    }

// Determine ELL width

#define CSR2ELL_DIM 512
    // Workspace size
    rocsparse_int blocks = (m - 1) / CSR2ELL_DIM + 1;

    // Allocate workspace
    rocsparse_int* workspace = NULL;
    RETURN_IF_HIP_ERROR(hipMalloc((void**)&workspace, sizeof(rocsparse_int) * blocks));

    // Compute maximum nnz per row
    hipLaunchKernelGGL((ell_width_kernel_part1<CSR2ELL_DIM>),
                       dim3(blocks),
                       dim3(CSR2ELL_DIM),
                       0,
                       stream,
                       m,
                       csr_row_ptr,
                       workspace);

    hipLaunchKernelGGL((ell_width_kernel_part2<CSR2ELL_DIM>),
                       dim3(1),
                       dim3(CSR2ELL_DIM),
                       0,
                       stream,
                       blocks,
                       workspace);

    // Copy ELL width back to host, if handle says so
    if(handle->pointer_mode == rocsparse_pointer_mode_device)
    {
        RETURN_IF_HIP_ERROR(
            hipMemcpyAsync(ell_width, workspace, sizeof(rocsparse_int), hipMemcpyDeviceToDevice, stream));
    }
    else
    {
        RETURN_IF_HIP_ERROR(
            hipMemcpy(ell_width, workspace, sizeof(rocsparse_int), hipMemcpyDeviceToHost));
    }

    // Free workspace
    RETURN_IF_HIP_ERROR(hipFree(workspace));

    return rocsparse_status_success;
}

extern "C" rocsparse_status rocsparse_scsr2ell(rocsparse_handle handle,
                                               rocsparse_int m,
                                               const rocsparse_mat_descr csr_descr,
                                               const float* csr_val,
                                               const rocsparse_int* csr_row_ptr,
                                               const rocsparse_int* csr_col_ind,
                                               const rocsparse_mat_descr ell_descr,
                                               rocsparse_int ell_width,
                                               float* ell_val,
                                               rocsparse_int* ell_col_ind)
{
    return rocsparse_csr2ell_template<float>(handle,
                                             m,
                                             csr_descr,
                                             csr_val,
                                             csr_row_ptr,
                                             csr_col_ind,
                                             ell_descr,
                                             ell_width,
                                             ell_val,
                                             ell_col_ind);
}

extern "C" rocsparse_status rocsparse_dcsr2ell(rocsparse_handle handle,
                                               rocsparse_int m,
                                               const rocsparse_mat_descr csr_descr,
                                               const double* csr_val,
                                               const rocsparse_int* csr_row_ptr,
                                               const rocsparse_int* csr_col_ind,
                                               const rocsparse_mat_descr ell_descr,
                                               rocsparse_int ell_width,
                                               double* ell_val,
                                               rocsparse_int* ell_col_ind)
{
    return rocsparse_csr2ell_template<double>(handle,
                                              m,
                                              csr_descr,
                                              csr_val,
                                              csr_row_ptr,
                                              csr_col_ind,
                                              ell_descr,
                                              ell_width,
                                              ell_val,
                                              ell_col_ind);
}
<|endoftext|>