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

#include "Commands.h"
#include "MessageImpl.h"
#include "Version.h"
#include "pulsar/MessageBuilder.h"
#include "LogUtils.h"
#include "checksum/ChecksumProvider.h"
#include <algorithm>
namespace pulsar {

using namespace pulsar::proto;

DECLARE_LOG_OBJECT();

SharedBuffer Commands::writeMessageWithSize(const BaseCommand& cmd) {
    size_t cmdSize = cmd.ByteSize();
    size_t frameSize = 4 + cmdSize;
    size_t bufferSize = 4 + frameSize;

    SharedBuffer buffer = SharedBuffer::allocate(bufferSize);

    buffer.writeUnsignedInt(frameSize);
    buffer.writeUnsignedInt(cmdSize);
    cmd.SerializeToArray(buffer.mutableData(), cmdSize);
    buffer.bytesWritten(cmdSize);
    return buffer;
}

SharedBuffer Commands::newPartitionMetadataRequest(BaseCommand& cmd, const std::string& topic, uint64_t requestId) {
    cmd.set_type(BaseCommand::PARTITIONED_METADATA);
    CommandPartitionedTopicMetadata* partitionMetadata = cmd.mutable_partitionmetadata();
    partitionMetadata->set_topic(topic);
    partitionMetadata->set_request_id(requestId);
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newLookup(BaseCommand& cmd, const std::string& topic, const bool authoritative,
                                 uint64_t requestId) {
    cmd.set_type(BaseCommand::LOOKUP);
    CommandLookupTopic* lookup = cmd.mutable_lookuptopic();
    lookup->set_topic(topic);
    lookup->set_authoritative(authoritative);
    lookup->set_request_id(requestId);
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newConsumerStats(BaseCommand& cmd, uint64_t consumerId, uint64_t requestId) {
    cmd.set_type(BaseCommand::CONSUMER_STATS);
    CommandConsumerStats* consumerStats = cmd.mutable_consumerstats();
    consumerStats->set_consumer_id(consumerId);
    consumerStats->set_request_id(requestId);
    return writeMessageWithSize(cmd);
}

PairSharedBuffer Commands::newSend(SharedBuffer& headers, BaseCommand& cmd,
                                   uint64_t producerId, uint64_t sequenceId, ChecksumType checksumType, const Message& msg) {
    const proto::MessageMetadata& metadata = msg.impl_->metadata;
    SharedBuffer& payload = msg.impl_->payload;

    cmd.set_type(BaseCommand::SEND);
    CommandSend* send = cmd.mutable_send();
    send->set_producer_id(producerId);
    send->set_sequence_id(sequenceId);

    // / Wire format
    // [TOTAL_SIZE] [CMD_SIZE][CMD] [MAGIC_NUMBER][CHECKSUM] [METADATA_SIZE][METADATA] [PAYLOAD]

    int cmdSize = cmd.ByteSize();
    int msgMetadataSize = metadata.ByteSize();
    int payloadSize = payload.readableBytes();

    int magicAndChecksumLength =
            (Crc32c == (checksumType)) ? (2 + 4 /* magic + checksumLength*/) : 0;
    bool includeChecksum = magicAndChecksumLength > 0;
    int headerContentSize = 4 + cmdSize + magicAndChecksumLength + 4 + msgMetadataSize;  // cmdLength + cmdSize + magicLength +
    // checksumSize + msgMetadataLength + msgMetadataSize
    int totalSize = headerContentSize + payloadSize;
    int headersSize = 4 + headerContentSize;  // totalSize + headerLength
    int checksumReaderIndex = -1;

    headers.reset();
    assert(headers.writableBytes() >= headersSize);
    headers.writeUnsignedInt(totalSize);  // External frame

    // Write cmd
    headers.writeUnsignedInt(cmdSize);
    cmd.SerializeToArray(headers.mutableData(), cmdSize);
    headers.bytesWritten(cmdSize);

    // Create checksum placeholder
    if (includeChecksum) {
        headers.writeUnsignedShort(magicCrc32c);
        checksumReaderIndex = headers.writerIndex();
        headers.skipBytes(checksumSize);  //skip 4 bytes of checksum
    }

    // Write metadata
    headers.writeUnsignedInt(msgMetadataSize);
    metadata.SerializeToArray(headers.mutableData(), msgMetadataSize);
    headers.bytesWritten(msgMetadataSize);

    PairSharedBuffer composite;
    composite.set(0, headers);
    composite.set(1, payload);

    // Write checksum at created checksum-placeholder
    if (includeChecksum) {
        int writeIndex = headers.writerIndex();
        int metadataStartIndex = checksumReaderIndex + checksumSize;
        uint32_t metadataChecksum = computeChecksum(
                0, headers.data() + metadataStartIndex, (writeIndex - metadataStartIndex));
        uint32_t computedChecksum = computeChecksum(metadataChecksum, payload.data(),
                                               payload.writerIndex());
        // set computed checksum
        headers.setWriterIndex(checksumReaderIndex);
        headers.writeUnsignedInt(computedChecksum);
        headers.setWriterIndex(writeIndex);
    }

    return composite;
}

SharedBuffer Commands::newConnect(const AuthenticationPtr& authentication) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::CONNECT);
    CommandConnect* connect = cmd.mutable_connect();
    connect->set_client_version(_PULSAR_VERSION_);
    connect->set_auth_method_name(authentication->getAuthMethodName());
    connect->set_protocol_version(ProtocolVersion_MAX);
    AuthenticationDataPtr authDataContent;
    if (authentication->getAuthData(authDataContent) == ResultOk && authDataContent->hasDataFromCommand()) {
        connect->set_auth_data(authDataContent->getCommandData());
    }
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newSubscribe(const std::string& topic, const std::string&subscription,
                                    uint64_t consumerId, uint64_t requestId,
                                    CommandSubscribe_SubType subType, const std::string& consumerName) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::SUBSCRIBE);
    CommandSubscribe* subscribe = cmd.mutable_subscribe();
    subscribe->set_topic(topic);
    subscribe->set_subscription(subscription);
    subscribe->set_subtype(subType);
    subscribe->set_consumer_id(consumerId);
    subscribe->set_request_id(requestId);
    subscribe->set_consumer_name(consumerName);

    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newUnsubscribe(uint64_t consumerId, uint64_t requestId) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::UNSUBSCRIBE);
    CommandUnsubscribe* unsubscribe = cmd.mutable_unsubscribe();
    unsubscribe->set_consumer_id(consumerId);
    unsubscribe->set_request_id(requestId);

    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newProducer(const std::string& topic, uint64_t producerId,
                                   const std::string& producerName, uint64_t requestId) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::PRODUCER);
    CommandProducer* producer = cmd.mutable_producer();
    producer->set_topic(topic);
    producer->set_producer_id(producerId);
    producer->set_request_id(requestId);

    if (!producerName.empty()) {
        producer->set_producer_name(producerName);
    }

    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newAck(uint64_t consumerId, const MessageIdData& messageId,
                              CommandAck_AckType ackType,
                              int validationError) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::ACK);
    CommandAck* ack = cmd.mutable_ack();
    ack->set_consumer_id(consumerId);
    ack->set_ack_type(ackType);
    if (CommandAck_AckType_IsValid(validationError)) {
        ack->set_validation_error((CommandAck_ValidationError) validationError);
    }
    *(ack->mutable_message_id()) = messageId;
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newFlow(uint64_t consumerId, uint32_t messagePermits) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::FLOW);
    CommandFlow* flow = cmd.mutable_flow();
    flow->set_consumer_id(consumerId);
    flow->set_messagepermits(messagePermits);
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newCloseProducer(uint64_t producerId, uint64_t requestId) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::CLOSE_PRODUCER);
    CommandCloseProducer* close = cmd.mutable_close_producer();
    close->set_producer_id(producerId);
    close->set_request_id(requestId);
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newCloseConsumer(uint64_t consumerId, uint64_t requestId) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::CLOSE_CONSUMER);
    CommandCloseConsumer* close = cmd.mutable_close_consumer();
    close->set_consumer_id(consumerId);
    close->set_request_id(requestId);
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newPing() {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::PING);
    cmd.mutable_ping();
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newPong() {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::PONG);
    cmd.mutable_pong();
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newRedeliverUnacknowledgedMessages(uint64_t consumerId) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::REDELIVER_UNACKNOWLEDGED_MESSAGES);
    CommandRedeliverUnacknowledgedMessages* command = cmd.mutable_redeliverunacknowledgedmessages();
    command->set_consumer_id(consumerId);
    return writeMessageWithSize(cmd);
}

std::string Commands::messageType(BaseCommand_Type type) {
    switch (type) {
        case BaseCommand::CONNECT:
            return "CONNECT";
            break;
        case BaseCommand::CONNECTED:
            return "CONNECTED";
            break;
        case BaseCommand::SUBSCRIBE:
            return "SUBSCRIBE";
            break;
        case BaseCommand::PRODUCER:
            return "PRODUCER";
            break;
        case BaseCommand::SEND:
            return "SEND";
            break;
        case BaseCommand::SEND_RECEIPT:
            return "SEND_RECEIPT";
            break;
        case BaseCommand::SEND_ERROR:
            return "SEND_ERROR";
            break;
        case BaseCommand::MESSAGE:
            return "MESSAGE";
            break;
        case BaseCommand::ACK:
            return "ACK";
            break;
        case BaseCommand::FLOW:
            return "FLOW";
            break;
        case BaseCommand::UNSUBSCRIBE:
            return "UNSUBSCRIBE";
            break;
        case BaseCommand::SUCCESS:
            return "SUCCESS";
            break;
        case BaseCommand::ERROR:
            return "ERROR";
            break;
        case BaseCommand::CLOSE_PRODUCER:
            return "CLOSE_PRODUCER";
            break;
        case BaseCommand::CLOSE_CONSUMER:
            return "CLOSE_CONSUMER";
            break;
        case BaseCommand::PRODUCER_SUCCESS:
            return "PRODUCER_SUCCESS";
            break;
        case BaseCommand::PING:
            return "PING";
            break;
        case BaseCommand::PONG:
            return "PONG";
            break;
        case BaseCommand::PARTITIONED_METADATA:
            return "PARTITIONED_METADATA";
            break;
        case BaseCommand::PARTITIONED_METADATA_RESPONSE:
            return "PARTITIONED_METADATA_RESPONSE";
            break;
        case BaseCommand::REDELIVER_UNACKNOWLEDGED_MESSAGES:
            return "REDELIVER_UNACKNOWLEDGED_MESSAGES";
            break;
        case BaseCommand::LOOKUP:
            return "LOOKUP";
            break;
        case BaseCommand::LOOKUP_RESPONSE:
            return "LOOKUP_RESPONSE";
            break;
        case BaseCommand::CONSUMER_STATS:
            return "CONSUMER_STATS";
            break;
        case BaseCommand::CONSUMER_STATS_RESPONSE:
            return "CONSUMER_STATS_RESPONSE";
            break;
    };
}

void Commands::initBatchMessageMetadata(const Message &msg, pulsar::proto::MessageMetadata &batchMetadata)
{
    if (msg.impl_->metadata.has_publish_time()) {
        batchMetadata.set_publish_time(msg.impl_->metadata.publish_time());
    }

    if (msg.impl_->metadata.has_sequence_id()) {
        batchMetadata.set_sequence_id(msg.impl_->metadata.sequence_id());
    }

    if (msg.impl_->metadata.has_replicated_from()) {
        batchMetadata.set_replicated_from(msg.impl_->metadata.replicated_from());
    }
}

void Commands::serializeSingleMessageInBatchWithPayload(const Message &msg,
                                                        SharedBuffer& batchPayLoad, const unsigned long& maxMessageSizeInBytes) {
    SingleMessageMetadata metadata;
    if (msg.impl_->hasPartitionKey()) {
        metadata.set_partition_key(msg.impl_->getPartitionKey());
    }

    for (MessageBuilder::StringMap::const_iterator it = msg.impl_->properties().begin();
            it != msg.impl_->properties().end(); it++) {
        proto::KeyValue *keyValue = proto::KeyValue().New();
        keyValue->set_key(it->first);
        keyValue->set_value(it->second);
        metadata.mutable_properties()->AddAllocated(keyValue);
    }

    // Format of batch message
    // Each Message = [METADATA_SIZE][METADATA] [PAYLOAD]

    int payloadSize = msg.impl_->payload.readableBytes();
    metadata.set_payload_size(payloadSize);

    int msgMetadataSize = metadata.ByteSize();

    unsigned long requiredSpace = sizeof(uint32_t) + msgMetadataSize + payloadSize;
    if (batchPayLoad.writableBytes() <= sizeof(uint32_t) + msgMetadataSize + payloadSize) {
        LOG_DEBUG("remaining size of batchPayLoad buffer [" << batchPayLoad.writableBytes() << "] can't accomodate new payload [" << requiredSpace << "] - expanding the batchPayload buffer");
        SharedBuffer buffer = SharedBuffer::allocate(batchPayLoad.readableBytes() +  std::max(requiredSpace, maxMessageSizeInBytes));
        // Adding batch created so far
        buffer.write(batchPayLoad.data(), batchPayLoad.readableBytes());
        batchPayLoad = buffer;
    }
    // Adding the new message
    batchPayLoad.writeUnsignedInt(msgMetadataSize);
    metadata.SerializeToArray(batchPayLoad.mutableData(), msgMetadataSize);
    batchPayLoad.bytesWritten(msgMetadataSize);
    batchPayLoad.write(msg.impl_->payload.data(), payloadSize);
}

Message Commands::deSerializeSingleMessageInBatch(Message& batchedMessage) {
    SharedBuffer& uncompressedPayload = batchedMessage.impl_->payload;

    // Format of batch message
    // Each Message = [METADATA_SIZE][METADATA] [PAYLOAD]

    const int& singleMetaSize = uncompressedPayload.readUnsignedInt();
    SingleMessageMetadata metadata;
    metadata.ParseFromArray(uncompressedPayload.data(), singleMetaSize);
    uncompressedPayload.consume(singleMetaSize);

    const int& payloadSize = metadata.payload_size();

    // Get a slice of size payloadSize from offset readIndex_
    SharedBuffer payload = uncompressedPayload.slice(0, payloadSize);
    uncompressedPayload.consume(payloadSize);

    Message singleMessage(batchedMessage.impl_->messageId, batchedMessage.impl_->metadata, payload,
                          metadata);
    singleMessage.impl_->cnx_ = batchedMessage.impl_->cnx_;

    return singleMessage;
}
}
/* namespace pulsar */
<commit_msg>C++ Client - fix for seeing correct msg rate in broker stats (#462)<commit_after>/**
 * Copyright 2016 Yahoo Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "Commands.h"
#include "MessageImpl.h"
#include "Version.h"
#include "pulsar/MessageBuilder.h"
#include "LogUtils.h"
#include "checksum/ChecksumProvider.h"
#include <algorithm>
namespace pulsar {

using namespace pulsar::proto;

DECLARE_LOG_OBJECT();

SharedBuffer Commands::writeMessageWithSize(const BaseCommand& cmd) {
    size_t cmdSize = cmd.ByteSize();
    size_t frameSize = 4 + cmdSize;
    size_t bufferSize = 4 + frameSize;

    SharedBuffer buffer = SharedBuffer::allocate(bufferSize);

    buffer.writeUnsignedInt(frameSize);
    buffer.writeUnsignedInt(cmdSize);
    cmd.SerializeToArray(buffer.mutableData(), cmdSize);
    buffer.bytesWritten(cmdSize);
    return buffer;
}

SharedBuffer Commands::newPartitionMetadataRequest(BaseCommand& cmd, const std::string& topic, uint64_t requestId) {
    cmd.set_type(BaseCommand::PARTITIONED_METADATA);
    CommandPartitionedTopicMetadata* partitionMetadata = cmd.mutable_partitionmetadata();
    partitionMetadata->set_topic(topic);
    partitionMetadata->set_request_id(requestId);
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newLookup(BaseCommand& cmd, const std::string& topic, const bool authoritative,
                                 uint64_t requestId) {
    cmd.set_type(BaseCommand::LOOKUP);
    CommandLookupTopic* lookup = cmd.mutable_lookuptopic();
    lookup->set_topic(topic);
    lookup->set_authoritative(authoritative);
    lookup->set_request_id(requestId);
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newConsumerStats(BaseCommand& cmd, uint64_t consumerId, uint64_t requestId) {
    cmd.set_type(BaseCommand::CONSUMER_STATS);
    CommandConsumerStats* consumerStats = cmd.mutable_consumerstats();
    consumerStats->set_consumer_id(consumerId);
    consumerStats->set_request_id(requestId);
    return writeMessageWithSize(cmd);
}

PairSharedBuffer Commands::newSend(SharedBuffer& headers, BaseCommand& cmd,
                                   uint64_t producerId, uint64_t sequenceId, ChecksumType checksumType, const Message& msg) {
    const proto::MessageMetadata& metadata = msg.impl_->metadata;
    SharedBuffer& payload = msg.impl_->payload;

    cmd.set_type(BaseCommand::SEND);
    CommandSend* send = cmd.mutable_send();
    send->set_producer_id(producerId);
    send->set_sequence_id(sequenceId);
    if (metadata.has_num_messages_in_batch()) {
        send->set_num_messages(metadata.num_messages_in_batch());
    }

    // / Wire format
    // [TOTAL_SIZE] [CMD_SIZE][CMD] [MAGIC_NUMBER][CHECKSUM] [METADATA_SIZE][METADATA] [PAYLOAD]

    int cmdSize = cmd.ByteSize();
    int msgMetadataSize = metadata.ByteSize();
    int payloadSize = payload.readableBytes();

    int magicAndChecksumLength =
            (Crc32c == (checksumType)) ? (2 + 4 /* magic + checksumLength*/) : 0;
    bool includeChecksum = magicAndChecksumLength > 0;
    int headerContentSize = 4 + cmdSize + magicAndChecksumLength + 4 + msgMetadataSize;  // cmdLength + cmdSize + magicLength +
    // checksumSize + msgMetadataLength + msgMetadataSize
    int totalSize = headerContentSize + payloadSize;
    int headersSize = 4 + headerContentSize;  // totalSize + headerLength
    int checksumReaderIndex = -1;

    headers.reset();
    assert(headers.writableBytes() >= headersSize);
    headers.writeUnsignedInt(totalSize);  // External frame

    // Write cmd
    headers.writeUnsignedInt(cmdSize);
    cmd.SerializeToArray(headers.mutableData(), cmdSize);
    headers.bytesWritten(cmdSize);

    // Create checksum placeholder
    if (includeChecksum) {
        headers.writeUnsignedShort(magicCrc32c);
        checksumReaderIndex = headers.writerIndex();
        headers.skipBytes(checksumSize);  //skip 4 bytes of checksum
    }

    // Write metadata
    headers.writeUnsignedInt(msgMetadataSize);
    metadata.SerializeToArray(headers.mutableData(), msgMetadataSize);
    headers.bytesWritten(msgMetadataSize);

    PairSharedBuffer composite;
    composite.set(0, headers);
    composite.set(1, payload);

    // Write checksum at created checksum-placeholder
    if (includeChecksum) {
        int writeIndex = headers.writerIndex();
        int metadataStartIndex = checksumReaderIndex + checksumSize;
        uint32_t metadataChecksum = computeChecksum(
                0, headers.data() + metadataStartIndex, (writeIndex - metadataStartIndex));
        uint32_t computedChecksum = computeChecksum(metadataChecksum, payload.data(),
                                               payload.writerIndex());
        // set computed checksum
        headers.setWriterIndex(checksumReaderIndex);
        headers.writeUnsignedInt(computedChecksum);
        headers.setWriterIndex(writeIndex);
    }

    return composite;
}

SharedBuffer Commands::newConnect(const AuthenticationPtr& authentication) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::CONNECT);
    CommandConnect* connect = cmd.mutable_connect();
    connect->set_client_version(_PULSAR_VERSION_);
    connect->set_auth_method_name(authentication->getAuthMethodName());
    connect->set_protocol_version(ProtocolVersion_MAX);
    AuthenticationDataPtr authDataContent;
    if (authentication->getAuthData(authDataContent) == ResultOk && authDataContent->hasDataFromCommand()) {
        connect->set_auth_data(authDataContent->getCommandData());
    }
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newSubscribe(const std::string& topic, const std::string&subscription,
                                    uint64_t consumerId, uint64_t requestId,
                                    CommandSubscribe_SubType subType, const std::string& consumerName) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::SUBSCRIBE);
    CommandSubscribe* subscribe = cmd.mutable_subscribe();
    subscribe->set_topic(topic);
    subscribe->set_subscription(subscription);
    subscribe->set_subtype(subType);
    subscribe->set_consumer_id(consumerId);
    subscribe->set_request_id(requestId);
    subscribe->set_consumer_name(consumerName);

    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newUnsubscribe(uint64_t consumerId, uint64_t requestId) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::UNSUBSCRIBE);
    CommandUnsubscribe* unsubscribe = cmd.mutable_unsubscribe();
    unsubscribe->set_consumer_id(consumerId);
    unsubscribe->set_request_id(requestId);

    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newProducer(const std::string& topic, uint64_t producerId,
                                   const std::string& producerName, uint64_t requestId) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::PRODUCER);
    CommandProducer* producer = cmd.mutable_producer();
    producer->set_topic(topic);
    producer->set_producer_id(producerId);
    producer->set_request_id(requestId);

    if (!producerName.empty()) {
        producer->set_producer_name(producerName);
    }

    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newAck(uint64_t consumerId, const MessageIdData& messageId,
                              CommandAck_AckType ackType,
                              int validationError) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::ACK);
    CommandAck* ack = cmd.mutable_ack();
    ack->set_consumer_id(consumerId);
    ack->set_ack_type(ackType);
    if (CommandAck_AckType_IsValid(validationError)) {
        ack->set_validation_error((CommandAck_ValidationError) validationError);
    }
    *(ack->mutable_message_id()) = messageId;
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newFlow(uint64_t consumerId, uint32_t messagePermits) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::FLOW);
    CommandFlow* flow = cmd.mutable_flow();
    flow->set_consumer_id(consumerId);
    flow->set_messagepermits(messagePermits);
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newCloseProducer(uint64_t producerId, uint64_t requestId) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::CLOSE_PRODUCER);
    CommandCloseProducer* close = cmd.mutable_close_producer();
    close->set_producer_id(producerId);
    close->set_request_id(requestId);
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newCloseConsumer(uint64_t consumerId, uint64_t requestId) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::CLOSE_CONSUMER);
    CommandCloseConsumer* close = cmd.mutable_close_consumer();
    close->set_consumer_id(consumerId);
    close->set_request_id(requestId);
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newPing() {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::PING);
    cmd.mutable_ping();
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newPong() {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::PONG);
    cmd.mutable_pong();
    return writeMessageWithSize(cmd);
}

SharedBuffer Commands::newRedeliverUnacknowledgedMessages(uint64_t consumerId) {
    BaseCommand cmd;
    cmd.set_type(BaseCommand::REDELIVER_UNACKNOWLEDGED_MESSAGES);
    CommandRedeliverUnacknowledgedMessages* command = cmd.mutable_redeliverunacknowledgedmessages();
    command->set_consumer_id(consumerId);
    return writeMessageWithSize(cmd);
}

std::string Commands::messageType(BaseCommand_Type type) {
    switch (type) {
        case BaseCommand::CONNECT:
            return "CONNECT";
            break;
        case BaseCommand::CONNECTED:
            return "CONNECTED";
            break;
        case BaseCommand::SUBSCRIBE:
            return "SUBSCRIBE";
            break;
        case BaseCommand::PRODUCER:
            return "PRODUCER";
            break;
        case BaseCommand::SEND:
            return "SEND";
            break;
        case BaseCommand::SEND_RECEIPT:
            return "SEND_RECEIPT";
            break;
        case BaseCommand::SEND_ERROR:
            return "SEND_ERROR";
            break;
        case BaseCommand::MESSAGE:
            return "MESSAGE";
            break;
        case BaseCommand::ACK:
            return "ACK";
            break;
        case BaseCommand::FLOW:
            return "FLOW";
            break;
        case BaseCommand::UNSUBSCRIBE:
            return "UNSUBSCRIBE";
            break;
        case BaseCommand::SUCCESS:
            return "SUCCESS";
            break;
        case BaseCommand::ERROR:
            return "ERROR";
            break;
        case BaseCommand::CLOSE_PRODUCER:
            return "CLOSE_PRODUCER";
            break;
        case BaseCommand::CLOSE_CONSUMER:
            return "CLOSE_CONSUMER";
            break;
        case BaseCommand::PRODUCER_SUCCESS:
            return "PRODUCER_SUCCESS";
            break;
        case BaseCommand::PING:
            return "PING";
            break;
        case BaseCommand::PONG:
            return "PONG";
            break;
        case BaseCommand::PARTITIONED_METADATA:
            return "PARTITIONED_METADATA";
            break;
        case BaseCommand::PARTITIONED_METADATA_RESPONSE:
            return "PARTITIONED_METADATA_RESPONSE";
            break;
        case BaseCommand::REDELIVER_UNACKNOWLEDGED_MESSAGES:
            return "REDELIVER_UNACKNOWLEDGED_MESSAGES";
            break;
        case BaseCommand::LOOKUP:
            return "LOOKUP";
            break;
        case BaseCommand::LOOKUP_RESPONSE:
            return "LOOKUP_RESPONSE";
            break;
        case BaseCommand::CONSUMER_STATS:
            return "CONSUMER_STATS";
            break;
        case BaseCommand::CONSUMER_STATS_RESPONSE:
            return "CONSUMER_STATS_RESPONSE";
            break;
    };
}

void Commands::initBatchMessageMetadata(const Message &msg, pulsar::proto::MessageMetadata &batchMetadata)
{
    if (msg.impl_->metadata.has_publish_time()) {
        batchMetadata.set_publish_time(msg.impl_->metadata.publish_time());
    }

    if (msg.impl_->metadata.has_sequence_id()) {
        batchMetadata.set_sequence_id(msg.impl_->metadata.sequence_id());
    }

    if (msg.impl_->metadata.has_replicated_from()) {
        batchMetadata.set_replicated_from(msg.impl_->metadata.replicated_from());
    }
}

void Commands::serializeSingleMessageInBatchWithPayload(const Message &msg,
                                                        SharedBuffer& batchPayLoad, const unsigned long& maxMessageSizeInBytes) {
    SingleMessageMetadata metadata;
    if (msg.impl_->hasPartitionKey()) {
        metadata.set_partition_key(msg.impl_->getPartitionKey());
    }

    for (MessageBuilder::StringMap::const_iterator it = msg.impl_->properties().begin();
            it != msg.impl_->properties().end(); it++) {
        proto::KeyValue *keyValue = proto::KeyValue().New();
        keyValue->set_key(it->first);
        keyValue->set_value(it->second);
        metadata.mutable_properties()->AddAllocated(keyValue);
    }

    // Format of batch message
    // Each Message = [METADATA_SIZE][METADATA] [PAYLOAD]

    int payloadSize = msg.impl_->payload.readableBytes();
    metadata.set_payload_size(payloadSize);

    int msgMetadataSize = metadata.ByteSize();

    unsigned long requiredSpace = sizeof(uint32_t) + msgMetadataSize + payloadSize;
    if (batchPayLoad.writableBytes() <= sizeof(uint32_t) + msgMetadataSize + payloadSize) {
        LOG_DEBUG("remaining size of batchPayLoad buffer [" << batchPayLoad.writableBytes() << "] can't accomodate new payload [" << requiredSpace << "] - expanding the batchPayload buffer");
        SharedBuffer buffer = SharedBuffer::allocate(batchPayLoad.readableBytes() +  std::max(requiredSpace, maxMessageSizeInBytes));
        // Adding batch created so far
        buffer.write(batchPayLoad.data(), batchPayLoad.readableBytes());
        batchPayLoad = buffer;
    }
    // Adding the new message
    batchPayLoad.writeUnsignedInt(msgMetadataSize);
    metadata.SerializeToArray(batchPayLoad.mutableData(), msgMetadataSize);
    batchPayLoad.bytesWritten(msgMetadataSize);
    batchPayLoad.write(msg.impl_->payload.data(), payloadSize);
}

Message Commands::deSerializeSingleMessageInBatch(Message& batchedMessage) {
    SharedBuffer& uncompressedPayload = batchedMessage.impl_->payload;

    // Format of batch message
    // Each Message = [METADATA_SIZE][METADATA] [PAYLOAD]

    const int& singleMetaSize = uncompressedPayload.readUnsignedInt();
    SingleMessageMetadata metadata;
    metadata.ParseFromArray(uncompressedPayload.data(), singleMetaSize);
    uncompressedPayload.consume(singleMetaSize);

    const int& payloadSize = metadata.payload_size();

    // Get a slice of size payloadSize from offset readIndex_
    SharedBuffer payload = uncompressedPayload.slice(0, payloadSize);
    uncompressedPayload.consume(payloadSize);

    Message singleMessage(batchedMessage.impl_->messageId, batchedMessage.impl_->metadata, payload,
                          metadata);
    singleMessage.impl_->cnx_ = batchedMessage.impl_->cnx_;

    return singleMessage;
}
}
/* namespace pulsar */
<|endoftext|>


<commit_before>/*
 * Copyright © 2012 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 * Authors:
 *    Eric Anholt <eric@anholt.net>
 *
 */

#include "brw_cfg.h"
#include "brw_fs_live_variables.h"

using namespace brw;

#define MAX_INSTRUCTION (1 << 30)

/** @file brw_fs_live_variables.cpp
 *
 * Support for calculating liveness information about virtual GRFs.
 *
 * This produces a live interval for each whole virtual GRF.  We could
 * choose to expose per-component live intervals for VGRFs of size > 1,
 * but we currently do not.  It is easier for the consumers of this
 * information to work with whole VGRFs.
 *
 * However, we internally track use/def information at the per-component
 * (reg_offset) level for greater accuracy.  Large VGRFs may be accessed
 * piecemeal over many (possibly non-adjacent) instructions.  In this case,
 * examining a single instruction is insufficient to decide whether a whole
 * VGRF is ultimately used or defined.  Tracking individual components
 * allows us to easily assemble this information.
 *
 * See Muchnick's Advanced Compiler Design and Implementation, section
 * 14.1 (p444).
 */

void
fs_live_variables::setup_one_read(bblock_t *block, fs_inst *inst,
                                  int ip, fs_reg reg)
{
   int var = var_from_vgrf[reg.reg] + reg.reg_offset;
   assert(var < num_vars);

   /* In most cases, a register can be written over safely by the
    * same instruction that is its last use.  For a single
    * instruction, the sources are dereferenced before writing of the
    * destination starts (naturally).  This gets more complicated for
    * simd16, because the instruction:
    *
    * add(16)      g4<1>F      g4<8,8,1>F   g6<8,8,1>F
    *
    * is actually decoded in hardware as:
    *
    * add(8)       g4<1>F      g4<8,8,1>F   g6<8,8,1>F
    * add(8)       g5<1>F      g5<8,8,1>F   g7<8,8,1>F
    *
    * Which is safe.  However, if we have uniform accesses
    * happening, we get into trouble:
    *
    * add(8)       g4<1>F      g4<0,1,0>F   g6<8,8,1>F
    * add(8)       g5<1>F      g4<0,1,0>F   g7<8,8,1>F
    *
    * Now our destination for the first instruction overwrote the
    * second instruction's src0, and we get garbage for those 8
    * pixels.  There's a similar issue for the pre-gen6
    * pixel_x/pixel_y, which are registers of 16-bit values and thus
    * would get stomped by the first decode as well.
    */
   int end_ip = ip;
   if (v->dispatch_width == 16 && (reg.stride == 0 ||
                                   (v->pixel_x.reg == reg.reg ||
                                    v->pixel_y.reg == reg.reg))) {
      end_ip++;
   }

   start[var] = MIN2(start[var], ip);
   end[var] = MAX2(end[var], end_ip);

   /* The use[] bitset marks when the block makes use of a variable (VGRF
    * channel) without having completely defined that variable within the
    * block.
    */
   if (!BITSET_TEST(bd[block->block_num].def, var))
      BITSET_SET(bd[block->block_num].use, var);
}

void
fs_live_variables::setup_one_write(bblock_t *block, fs_inst *inst,
                                   int ip, fs_reg reg)
{
   int var = var_from_vgrf[reg.reg] + reg.reg_offset;
   assert(var < num_vars);

   start[var] = MIN2(start[var], ip);
   end[var] = MAX2(end[var], ip);

   /* The def[] bitset marks when an initialization in a block completely
    * screens off previous updates of that variable (VGRF channel).
    */
   if (inst->dst.file == GRF && !inst->is_partial_write()) {
      if (!BITSET_TEST(bd[block->block_num].use, var))
         BITSET_SET(bd[block->block_num].def, var);
   }
}

/**
 * Sets up the use[] and def[] bitsets.
 *
 * The basic-block-level live variable analysis needs to know which
 * variables get used before they're completely defined, and which
 * variables are completely defined before they're used.
 *
 * These are tracked at the per-component level, rather than whole VGRFs.
 */
void
fs_live_variables::setup_def_use()
{
   int ip = 0;

   for (int b = 0; b < cfg->num_blocks; b++) {
      bblock_t *block = cfg->blocks[b];

      assert(ip == block->start_ip);
      if (b > 0)
	 assert(cfg->blocks[b - 1]->end_ip == ip - 1);

      for (fs_inst *inst = (fs_inst *)block->start;
	   inst != block->end->next;
	   inst = (fs_inst *)inst->next) {

	 /* Set use[] for this instruction */
	 for (unsigned int i = 0; i < 3; i++) {
            fs_reg reg = inst->src[i];

            if (reg.file != GRF)
               continue;

            for (int j = 0; j < inst->regs_read(v, i); j++) {
               setup_one_read(block, inst, ip, reg);
               reg.reg_offset++;
            }
	 }

         /* Set def[] for this instruction */
         if (inst->dst.file == GRF) {
            fs_reg reg = inst->dst;
            for (int j = 0; j < inst->regs_written; j++) {
               setup_one_write(block, inst, ip, reg);
               reg.reg_offset++;
            }
	 }

	 ip++;
      }
   }
}

/**
 * The algorithm incrementally sets bits in liveout and livein,
 * propagating it through control flow.  It will eventually terminate
 * because it only ever adds bits, and stops when no bits are added in
 * a pass.
 */
void
fs_live_variables::compute_live_variables()
{
   bool cont = true;

   while (cont) {
      cont = false;

      for (int b = 0; b < cfg->num_blocks; b++) {
	 /* Update livein */
	 for (int i = 0; i < bitset_words; i++) {
            BITSET_WORD new_livein = (bd[b].use[i] |
                                      (bd[b].liveout[i] & ~bd[b].def[i]));
	    if (new_livein & ~bd[b].livein[i]) {
               bd[b].livein[i] |= new_livein;
               cont = true;
	    }
	 }

	 /* Update liveout */
	 foreach_list(block_node, &cfg->blocks[b]->children) {
	    bblock_link *link = (bblock_link *)block_node;
	    bblock_t *block = link->block;

	    for (int i = 0; i < bitset_words; i++) {
               BITSET_WORD new_liveout = (bd[block->block_num].livein[i] &
                                          ~bd[b].liveout[i]);
               if (new_liveout) {
                  bd[b].liveout[i] |= new_liveout;
                  cont = true;
               }
	    }
	 }
      }
   }
}

/**
 * Extend the start/end ranges for each variable to account for the
 * new information calculated from control flow.
 */
void
fs_live_variables::compute_start_end()
{
   for (int b = 0; b < cfg->num_blocks; b++) {
      for (int i = 0; i < num_vars; i++) {
	 if (BITSET_TEST(bd[b].livein, i)) {
	    start[i] = MIN2(start[i], cfg->blocks[b]->start_ip);
	    end[i] = MAX2(end[i], cfg->blocks[b]->start_ip);
	 }

	 if (BITSET_TEST(bd[b].liveout, i)) {
	    start[i] = MIN2(start[i], cfg->blocks[b]->end_ip);
	    end[i] = MAX2(end[i], cfg->blocks[b]->end_ip);
	 }

      }
   }
}

int
fs_live_variables::var_from_reg(fs_reg *reg)
{
   return var_from_vgrf[reg->reg] + reg->reg_offset;
}

fs_live_variables::fs_live_variables(fs_visitor *v, cfg_t *cfg)
   : v(v), cfg(cfg)
{
   mem_ctx = ralloc_context(NULL);

   num_vgrfs = v->virtual_grf_count;
   num_vars = 0;
   var_from_vgrf = rzalloc_array(mem_ctx, int, num_vgrfs);
   for (int i = 0; i < num_vgrfs; i++) {
      var_from_vgrf[i] = num_vars;
      num_vars += v->virtual_grf_sizes[i];
   }

   vgrf_from_var = rzalloc_array(mem_ctx, int, num_vars);
   for (int i = 0; i < num_vgrfs; i++) {
      for (int j = 0; j < v->virtual_grf_sizes[i]; j++) {
         vgrf_from_var[var_from_vgrf[i] + j] = i;
      }
   }

   start = ralloc_array(mem_ctx, int, num_vars);
   end = rzalloc_array(mem_ctx, int, num_vars);
   for (int i = 0; i < num_vars; i++) {
      start[i] = MAX_INSTRUCTION;
      end[i] = -1;
   }

   bd = rzalloc_array(mem_ctx, struct block_data, cfg->num_blocks);

   bitset_words = BITSET_WORDS(num_vars);
   for (int i = 0; i < cfg->num_blocks; i++) {
      bd[i].def = rzalloc_array(mem_ctx, BITSET_WORD, bitset_words);
      bd[i].use = rzalloc_array(mem_ctx, BITSET_WORD, bitset_words);
      bd[i].livein = rzalloc_array(mem_ctx, BITSET_WORD, bitset_words);
      bd[i].liveout = rzalloc_array(mem_ctx, BITSET_WORD, bitset_words);
   }

   setup_def_use();
   compute_live_variables();
   compute_start_end();
}

fs_live_variables::~fs_live_variables()
{
   ralloc_free(mem_ctx);
}

void
fs_visitor::invalidate_live_intervals()
{
   ralloc_free(live_intervals);
   live_intervals = NULL;
}

/**
 * Compute the live intervals for each virtual GRF.
 *
 * This uses the per-component use/def data, but combines it to produce
 * information about whole VGRFs.
 */
void
fs_visitor::calculate_live_intervals()
{
   if (this->live_intervals)
      return;

   int num_vgrfs = this->virtual_grf_count;
   ralloc_free(this->virtual_grf_start);
   ralloc_free(this->virtual_grf_end);
   virtual_grf_start = ralloc_array(mem_ctx, int, num_vgrfs);
   virtual_grf_end = ralloc_array(mem_ctx, int, num_vgrfs);

   for (int i = 0; i < num_vgrfs; i++) {
      virtual_grf_start[i] = MAX_INSTRUCTION;
      virtual_grf_end[i] = -1;
   }

   cfg_t cfg(&instructions);
   this->live_intervals = new(mem_ctx) fs_live_variables(this, &cfg);

   /* Merge the per-component live ranges to whole VGRF live ranges. */
   for (int i = 0; i < live_intervals->num_vars; i++) {
      int vgrf = live_intervals->vgrf_from_var[i];
      virtual_grf_start[vgrf] = MIN2(virtual_grf_start[vgrf],
                                     live_intervals->start[i]);
      virtual_grf_end[vgrf] = MAX2(virtual_grf_end[vgrf],
                                   live_intervals->end[i]);
   }
}

bool
fs_live_variables::vars_interfere(int a, int b)
{
   return !(end[b] <= start[a] ||
            end[a] <= start[b]);
}

bool
fs_visitor::virtual_grf_interferes(int a, int b)
{
   return !(virtual_grf_end[a] <= virtual_grf_start[b] ||
            virtual_grf_end[b] <= virtual_grf_start[a]);
}
<commit_msg>i965/fs: Fix vgrf0 live interval when no interpolation was done.<commit_after>/*
 * Copyright © 2012 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 * Authors:
 *    Eric Anholt <eric@anholt.net>
 *
 */

#include "brw_cfg.h"
#include "brw_fs_live_variables.h"

using namespace brw;

#define MAX_INSTRUCTION (1 << 30)

/** @file brw_fs_live_variables.cpp
 *
 * Support for calculating liveness information about virtual GRFs.
 *
 * This produces a live interval for each whole virtual GRF.  We could
 * choose to expose per-component live intervals for VGRFs of size > 1,
 * but we currently do not.  It is easier for the consumers of this
 * information to work with whole VGRFs.
 *
 * However, we internally track use/def information at the per-component
 * (reg_offset) level for greater accuracy.  Large VGRFs may be accessed
 * piecemeal over many (possibly non-adjacent) instructions.  In this case,
 * examining a single instruction is insufficient to decide whether a whole
 * VGRF is ultimately used or defined.  Tracking individual components
 * allows us to easily assemble this information.
 *
 * See Muchnick's Advanced Compiler Design and Implementation, section
 * 14.1 (p444).
 */

void
fs_live_variables::setup_one_read(bblock_t *block, fs_inst *inst,
                                  int ip, fs_reg reg)
{
   int var = var_from_vgrf[reg.reg] + reg.reg_offset;
   assert(var < num_vars);

   /* In most cases, a register can be written over safely by the
    * same instruction that is its last use.  For a single
    * instruction, the sources are dereferenced before writing of the
    * destination starts (naturally).  This gets more complicated for
    * simd16, because the instruction:
    *
    * add(16)      g4<1>F      g4<8,8,1>F   g6<8,8,1>F
    *
    * is actually decoded in hardware as:
    *
    * add(8)       g4<1>F      g4<8,8,1>F   g6<8,8,1>F
    * add(8)       g5<1>F      g5<8,8,1>F   g7<8,8,1>F
    *
    * Which is safe.  However, if we have uniform accesses
    * happening, we get into trouble:
    *
    * add(8)       g4<1>F      g4<0,1,0>F   g6<8,8,1>F
    * add(8)       g5<1>F      g4<0,1,0>F   g7<8,8,1>F
    *
    * Now our destination for the first instruction overwrote the
    * second instruction's src0, and we get garbage for those 8
    * pixels.  There's a similar issue for the pre-gen6
    * pixel_x/pixel_y, which are registers of 16-bit values and thus
    * would get stomped by the first decode as well.
    */
   int end_ip = ip;
   if (v->dispatch_width == 16 && (reg.stride == 0 ||
                                   ((v->pixel_x.file == GRF &&
                                     v->pixel_x.reg == reg.reg) ||
                                    (v->pixel_y.file == GRF &&
                                     v->pixel_y.reg == reg.reg)))) {
      end_ip++;
   }

   start[var] = MIN2(start[var], ip);
   end[var] = MAX2(end[var], end_ip);

   /* The use[] bitset marks when the block makes use of a variable (VGRF
    * channel) without having completely defined that variable within the
    * block.
    */
   if (!BITSET_TEST(bd[block->block_num].def, var))
      BITSET_SET(bd[block->block_num].use, var);
}

void
fs_live_variables::setup_one_write(bblock_t *block, fs_inst *inst,
                                   int ip, fs_reg reg)
{
   int var = var_from_vgrf[reg.reg] + reg.reg_offset;
   assert(var < num_vars);

   start[var] = MIN2(start[var], ip);
   end[var] = MAX2(end[var], ip);

   /* The def[] bitset marks when an initialization in a block completely
    * screens off previous updates of that variable (VGRF channel).
    */
   if (inst->dst.file == GRF && !inst->is_partial_write()) {
      if (!BITSET_TEST(bd[block->block_num].use, var))
         BITSET_SET(bd[block->block_num].def, var);
   }
}

/**
 * Sets up the use[] and def[] bitsets.
 *
 * The basic-block-level live variable analysis needs to know which
 * variables get used before they're completely defined, and which
 * variables are completely defined before they're used.
 *
 * These are tracked at the per-component level, rather than whole VGRFs.
 */
void
fs_live_variables::setup_def_use()
{
   int ip = 0;

   for (int b = 0; b < cfg->num_blocks; b++) {
      bblock_t *block = cfg->blocks[b];

      assert(ip == block->start_ip);
      if (b > 0)
	 assert(cfg->blocks[b - 1]->end_ip == ip - 1);

      for (fs_inst *inst = (fs_inst *)block->start;
	   inst != block->end->next;
	   inst = (fs_inst *)inst->next) {

	 /* Set use[] for this instruction */
	 for (unsigned int i = 0; i < 3; i++) {
            fs_reg reg = inst->src[i];

            if (reg.file != GRF)
               continue;

            for (int j = 0; j < inst->regs_read(v, i); j++) {
               setup_one_read(block, inst, ip, reg);
               reg.reg_offset++;
            }
	 }

         /* Set def[] for this instruction */
         if (inst->dst.file == GRF) {
            fs_reg reg = inst->dst;
            for (int j = 0; j < inst->regs_written; j++) {
               setup_one_write(block, inst, ip, reg);
               reg.reg_offset++;
            }
	 }

	 ip++;
      }
   }
}

/**
 * The algorithm incrementally sets bits in liveout and livein,
 * propagating it through control flow.  It will eventually terminate
 * because it only ever adds bits, and stops when no bits are added in
 * a pass.
 */
void
fs_live_variables::compute_live_variables()
{
   bool cont = true;

   while (cont) {
      cont = false;

      for (int b = 0; b < cfg->num_blocks; b++) {
	 /* Update livein */
	 for (int i = 0; i < bitset_words; i++) {
            BITSET_WORD new_livein = (bd[b].use[i] |
                                      (bd[b].liveout[i] & ~bd[b].def[i]));
	    if (new_livein & ~bd[b].livein[i]) {
               bd[b].livein[i] |= new_livein;
               cont = true;
	    }
	 }

	 /* Update liveout */
	 foreach_list(block_node, &cfg->blocks[b]->children) {
	    bblock_link *link = (bblock_link *)block_node;
	    bblock_t *block = link->block;

	    for (int i = 0; i < bitset_words; i++) {
               BITSET_WORD new_liveout = (bd[block->block_num].livein[i] &
                                          ~bd[b].liveout[i]);
               if (new_liveout) {
                  bd[b].liveout[i] |= new_liveout;
                  cont = true;
               }
	    }
	 }
      }
   }
}

/**
 * Extend the start/end ranges for each variable to account for the
 * new information calculated from control flow.
 */
void
fs_live_variables::compute_start_end()
{
   for (int b = 0; b < cfg->num_blocks; b++) {
      for (int i = 0; i < num_vars; i++) {
	 if (BITSET_TEST(bd[b].livein, i)) {
	    start[i] = MIN2(start[i], cfg->blocks[b]->start_ip);
	    end[i] = MAX2(end[i], cfg->blocks[b]->start_ip);
	 }

	 if (BITSET_TEST(bd[b].liveout, i)) {
	    start[i] = MIN2(start[i], cfg->blocks[b]->end_ip);
	    end[i] = MAX2(end[i], cfg->blocks[b]->end_ip);
	 }

      }
   }
}

int
fs_live_variables::var_from_reg(fs_reg *reg)
{
   return var_from_vgrf[reg->reg] + reg->reg_offset;
}

fs_live_variables::fs_live_variables(fs_visitor *v, cfg_t *cfg)
   : v(v), cfg(cfg)
{
   mem_ctx = ralloc_context(NULL);

   num_vgrfs = v->virtual_grf_count;
   num_vars = 0;
   var_from_vgrf = rzalloc_array(mem_ctx, int, num_vgrfs);
   for (int i = 0; i < num_vgrfs; i++) {
      var_from_vgrf[i] = num_vars;
      num_vars += v->virtual_grf_sizes[i];
   }

   vgrf_from_var = rzalloc_array(mem_ctx, int, num_vars);
   for (int i = 0; i < num_vgrfs; i++) {
      for (int j = 0; j < v->virtual_grf_sizes[i]; j++) {
         vgrf_from_var[var_from_vgrf[i] + j] = i;
      }
   }

   start = ralloc_array(mem_ctx, int, num_vars);
   end = rzalloc_array(mem_ctx, int, num_vars);
   for (int i = 0; i < num_vars; i++) {
      start[i] = MAX_INSTRUCTION;
      end[i] = -1;
   }

   bd = rzalloc_array(mem_ctx, struct block_data, cfg->num_blocks);

   bitset_words = BITSET_WORDS(num_vars);
   for (int i = 0; i < cfg->num_blocks; i++) {
      bd[i].def = rzalloc_array(mem_ctx, BITSET_WORD, bitset_words);
      bd[i].use = rzalloc_array(mem_ctx, BITSET_WORD, bitset_words);
      bd[i].livein = rzalloc_array(mem_ctx, BITSET_WORD, bitset_words);
      bd[i].liveout = rzalloc_array(mem_ctx, BITSET_WORD, bitset_words);
   }

   setup_def_use();
   compute_live_variables();
   compute_start_end();
}

fs_live_variables::~fs_live_variables()
{
   ralloc_free(mem_ctx);
}

void
fs_visitor::invalidate_live_intervals()
{
   ralloc_free(live_intervals);
   live_intervals = NULL;
}

/**
 * Compute the live intervals for each virtual GRF.
 *
 * This uses the per-component use/def data, but combines it to produce
 * information about whole VGRFs.
 */
void
fs_visitor::calculate_live_intervals()
{
   if (this->live_intervals)
      return;

   int num_vgrfs = this->virtual_grf_count;
   ralloc_free(this->virtual_grf_start);
   ralloc_free(this->virtual_grf_end);
   virtual_grf_start = ralloc_array(mem_ctx, int, num_vgrfs);
   virtual_grf_end = ralloc_array(mem_ctx, int, num_vgrfs);

   for (int i = 0; i < num_vgrfs; i++) {
      virtual_grf_start[i] = MAX_INSTRUCTION;
      virtual_grf_end[i] = -1;
   }

   cfg_t cfg(&instructions);
   this->live_intervals = new(mem_ctx) fs_live_variables(this, &cfg);

   /* Merge the per-component live ranges to whole VGRF live ranges. */
   for (int i = 0; i < live_intervals->num_vars; i++) {
      int vgrf = live_intervals->vgrf_from_var[i];
      virtual_grf_start[vgrf] = MIN2(virtual_grf_start[vgrf],
                                     live_intervals->start[i]);
      virtual_grf_end[vgrf] = MAX2(virtual_grf_end[vgrf],
                                   live_intervals->end[i]);
   }
}

bool
fs_live_variables::vars_interfere(int a, int b)
{
   return !(end[b] <= start[a] ||
            end[a] <= start[b]);
}

bool
fs_visitor::virtual_grf_interferes(int a, int b)
{
   return !(virtual_grf_end[a] <= virtual_grf_start[b] ||
            virtual_grf_end[b] <= virtual_grf_start[a]);
}
<|endoftext|>


<commit_before>#include "include/calculator.h"
#include <assert.h>

#define GET_POINT(n, on_y_axis) ((on_y_axis) ? get_point(n) : get_point(0, n))

Calculator::Calculator(MoveListener *lis) : Constructor(lis) {}

Calculator::~Calculator() {}

const Point *Calculator::get_point(constr_num x, constr_num y)
{
    Point *p = new Point(x, y);

    if (add_point(p)) // doesn't add to cli
        return p;
    delete p;
    return nullptr;
}

const Point *Calculator::get_add(constr_num a, constr_num b, bool on_y_axis)
{
    const Point *pa = GET_POINT(a, on_y_axis),
                *pb = GET_POINT(b, on_y_axis),
                *p  = GET_POINT(a + b, on_y_axis);

    if (pa == nullptr || pb == nullptr)
        return nullptr;
    if (p != nullptr)
        return p;

    auto *l = join_segment(*origin, *pb);
    if (l == nullptr) // b = 0
        return pa;

    l = translate(*l, *pa);
    assert(l != nullptr); // translate only returns null for arguments not contained

    return &l->end;
}

const Point *Calculator::get_sub(constr_num a, constr_num b, bool on_y_axis)
{
    const Point *pa = GET_POINT(a, on_y_axis),
                *pb = GET_POINT(b, on_y_axis),
                *p  = GET_POINT(a - b, on_y_axis);

    if (pa == nullptr || pb == nullptr)
        return nullptr;
    if (p != nullptr)
        return p;

    auto *l = join_segment(*pb, *origin);
    if (l == nullptr) // b = 0
        return pa;

    l = translate(*l, *pa);
    assert(l != nullptr); // translate only returns null for arguments not contained

    return &l->end;
}

const Point *Calculator::get_mul(constr_num a, constr_num b, bool on_y_axis)
{
    const Point *pa = GET_POINT(a, on_y_axis),
                *pb = GET_POINT(b, !on_y_axis),
                *p  = GET_POINT(a * b, on_y_axis);

    if (pa == nullptr || pb == nullptr)
        return nullptr;
    if (p != nullptr)
        return p;

    auto *l = join_line(*pa, on_y_axis ? *unit_x : *unit_y);
    assert(l != nullptr);

    return meet(*parallel(*l, *pb), on_y_axis ? *y_axis : *x_axis); // both l and pb are contained
}

const Point *Calculator::get_div(constr_num a, constr_num b, bool on_y_axis)
{
    if (b == 0)
        return nullptr;

    const Point *pa = GET_POINT(a, on_y_axis),
                *pb = GET_POINT(b, !on_y_axis),
                *p  = GET_POINT(a / b, on_y_axis);

    if (pa == nullptr || pb == nullptr)
        return nullptr;
    if (p != nullptr)
        return p;

    auto *l = join_line(*pa, *pb);
    assert(l != nullptr); // true only if a = b = 0

    return meet(*parallel(*l, on_y_axis ? *unit_x : *unit_y), on_y_axis ? *y_axis : *x_axis); // both l and unit_y are contained
}

const Point *Calculator::get_sqrt(constr_num a, bool on_y_axis)
{
    const Point *pa =  GET_POINT(a, on_y_axis),
                *neg = GET_POINT(-1, on_y_axis),
                *p   = GET_POINT(sqrt(a), on_y_axis);

    if (pa == nullptr || a < 0)
        return nullptr;
    if (a == 0)
        return origin;
    if (p != nullptr)
        return p;

    auto *center = midpoint(*neg, *pa);
    assert(center != nullptr); // both neg and pa are contained

    auto meets = meet(on_y_axis ? *y_axis : *x_axis, *join_circle(*center, *pa)); // circle will always exist, as center != pa

    return (on_y_axis ? meets.first->x : meets.first->y) < 0 ? meets.second : meets.first; // (0, √a)
}

// TODO check for subtraction and division for binary operations
const Point *Calculator::construct_number(constr_num n, bool on_y_axis)
{
    switch (n.expr->type) {
    case 0:
        return GET_POINT(n, on_y_axis);
    case 1:
        construct_number(n.expr->expr_union.unary.arg);
        switch (n.expr->expr_union.unary.op) {
        case 1:
            return get_sub(0, n.expr->expr_union.unary.arg, on_y_axis);
        case 2:
            return get_div(1, n.expr->expr_union.unary.arg, on_y_axis);
        default:
            return get_sqrt(n.expr->expr_union.unary.arg, on_y_axis);
        }
    default:
        construct_number(n.expr->expr_union.binary.arg1);
        construct_number(n.expr->expr_union.binary.arg2);
        switch (n.expr->expr_union.binary.op) {
        case 1:
            return get_add(n.expr->expr_union.binary.arg1,
                           n.expr->expr_union.binary.arg2, on_y_axis);
        default:
            return get_mul(n.expr->expr_union.binary.arg1,
                           n.expr->expr_union.binary.arg2, on_y_axis);
        }
    }
}

const Point *Calculator::construct_point(const Point &p)
{
    const Point *px = construct_number(p.x),
                *py = construct_number(p.y, true);

    if (px == nullptr || py == nullptr)
        return nullptr;

    return meet(*parallel(*x_axis, *py),
                *parallel(*y_axis, *px));
}
<commit_msg>Fixed pointer error for construct_number<commit_after>#include "include/calculator.h"
#include <assert.h>

#define GET_POINT(n, on_y_axis) ((on_y_axis) ? get_point(n) : get_point(0, n))

Calculator::Calculator(MoveListener *lis) : Constructor(lis) {}

Calculator::~Calculator() {}

const Point *Calculator::get_point(constr_num x, constr_num y)
{
    Point *p = new Point(x, y);

    if (add_point(p)) // doesn't add to cli
        return p;
    delete p;
    return nullptr;
}

const Point *Calculator::get_add(constr_num a, constr_num b, bool on_y_axis)
{
    const Point *pa = GET_POINT(a, on_y_axis),
                *pb = GET_POINT(b, on_y_axis),
                *p  = GET_POINT(a + b, on_y_axis);

    if (pa == nullptr || pb == nullptr)
        return nullptr;
    if (p != nullptr)
        return p;

    auto *l = join_segment(*origin, *pb);
    if (l == nullptr) // b = 0
        return pa;

    l = translate(*l, *pa);
    assert(l != nullptr); // translate only returns null for arguments not contained

    return &l->end;
}

const Point *Calculator::get_sub(constr_num a, constr_num b, bool on_y_axis)
{
    const Point *pa = GET_POINT(a, on_y_axis),
                *pb = GET_POINT(b, on_y_axis),
                *p  = GET_POINT(a - b, on_y_axis);

    if (pa == nullptr || pb == nullptr)
        return nullptr;
    if (p != nullptr)
        return p;

    auto *l = join_segment(*pb, *origin);
    if (l == nullptr) // b = 0
        return pa;

    l = translate(*l, *pa);
    assert(l != nullptr); // translate only returns null for arguments not contained

    return &l->end;
}

const Point *Calculator::get_mul(constr_num a, constr_num b, bool on_y_axis)
{
    const Point *pa = GET_POINT(a, on_y_axis),
                *pb = GET_POINT(b, !on_y_axis),
                *p  = GET_POINT(a * b, on_y_axis);

    if (pa == nullptr || pb == nullptr)
        return nullptr;
    if (p != nullptr)
        return p;

    auto *l = join_line(*pa, on_y_axis ? *unit_x : *unit_y);
    assert(l != nullptr);

    return meet(*parallel(*l, *pb), on_y_axis ? *y_axis : *x_axis); // both l and pb are contained
}

const Point *Calculator::get_div(constr_num a, constr_num b, bool on_y_axis)
{
    if (b == 0)
        return nullptr;

    const Point *pa = GET_POINT(a, on_y_axis),
                *pb = GET_POINT(b, !on_y_axis),
                *p  = GET_POINT(a / b, on_y_axis);

    if (pa == nullptr || pb == nullptr)
        return nullptr;
    if (p != nullptr)
        return p;

    auto *l = join_line(*pa, *pb);
    assert(l != nullptr); // true only if a = b = 0

    return meet(*parallel(*l, on_y_axis ? *unit_x : *unit_y), on_y_axis ? *y_axis : *x_axis); // both l and unit_y are contained
}

const Point *Calculator::get_sqrt(constr_num a, bool on_y_axis)
{
    const Point *pa =  GET_POINT(a, on_y_axis),
                *neg = GET_POINT(-1, on_y_axis),
                *p   = GET_POINT(sqrt(a), on_y_axis);

    if (pa == nullptr || a < 0)
        return nullptr;
    if (a == 0)
        return origin;
    if (p != nullptr)
        return p;

    auto *center = midpoint(*neg, *pa);
    assert(center != nullptr); // both neg and pa are contained

    auto meets = meet(on_y_axis ? *y_axis : *x_axis, *join_circle(*center, *pa)); // circle will always exist, as center != pa

    return (on_y_axis ? meets.first->x : meets.first->y) < 0 ? meets.second : meets.first; // (0, √a)
}

// TODO check for subtraction and division for binary operations
const Point *Calculator::construct_number(constr_num n, bool on_y_axis)
{
    switch (n.expr->type) {
    case 0:
        return GET_POINT(n, on_y_axis);
    case 1:
        construct_number(n.copy(n.expr->expr_union.unary.arg));
        switch (n.expr->expr_union.unary.op) {
        case 1:
            return get_sub(0, n.copy(n.expr->expr_union.unary.arg), on_y_axis);
        case 2:
            return get_div(1, n.copy(n.expr->expr_union.unary.arg), on_y_axis);
        default:
            return get_sqrt(n.copy(n.expr->expr_union.unary.arg), on_y_axis);
        }
    default:
        construct_number(n.copy(n.expr->expr_union.binary.arg1));
        construct_number(n.copy(n.expr->expr_union.binary.arg2));
        switch (n.expr->expr_union.binary.op) {
        case 1:
            return get_add(n.copy(n.expr->expr_union.binary.arg1),
                           n.copy(n.expr->expr_union.binary.arg2), on_y_axis);
        default:
            return get_mul(n.copy(n.expr->expr_union.binary.arg1),
                           n.copy(n.expr->expr_union.binary.arg2), on_y_axis);
        }
    }
}

const Point *Calculator::construct_point(const Point &p)
{
    const Point *px = construct_number(p.x),
                *py = construct_number(p.y, true);

    if (px == nullptr || py == nullptr)
        return nullptr;

    return meet(*parallel(*x_axis, *py),
                *parallel(*y_axis, *px));
}
<|endoftext|>


<commit_before>#pragma once

#include <boost/optional.hpp>
#include <rai/config.hpp>
#include <rai/lib/numbers.hpp>
#include <rai/lib/utility.hpp>

#include <atomic>
#include <memory>
#include <thread>

namespace rai
{
class block;
bool work_validate (rai::block_hash const &, uint64_t);
bool work_validate (rai::block const &);
uint64_t work_value (rai::block_hash const &, uint64_t);
class opencl_work;
class work_pool
{
public:
	work_pool (unsigned, std::function <boost::optional <uint64_t> (rai::uint256_union const &)> = nullptr);
	~work_pool ();
	void loop (uint64_t);
	void stop ();
	void cancel (rai::uint256_union const &);
	void generate (rai::uint256_union const &, std::function <void (boost::optional <uint64_t> const &)>);
	uint64_t generate (rai::uint256_union const &);
	std::atomic <int> ticket;
	bool done;
	std::vector <std::thread> threads;
	std::list <std::pair <rai::uint256_union, std::function <void (boost::optional <uint64_t> const &)>>> pending;
	std::mutex mutex;
	std::condition_variable producer_condition;
	std::function <boost::optional<uint64_t> (rai::uint256_union const &)> opencl;
	rai::observer_set <bool> work_observers;
	// Local work threshold for rate-limiting publishing blocks. ~5 seconds of work.
	static uint64_t const publish_test_threshold = 0xff00000000000000;
	static uint64_t const publish_full_threshold = 0xffffffc000000000;
	static uint64_t const publish_threshold = rai::rai_network == rai::rai_networks::rai_test_network ? publish_test_threshold : publish_full_threshold;
};
}

<commit_msg>add <condition_variable> include<commit_after>#pragma once

#include <boost/optional.hpp>
#include <rai/config.hpp>
#include <rai/lib/numbers.hpp>
#include <rai/lib/utility.hpp>

#include <atomic>
#include <memory>
#include <thread>
#include <condition_variable>

namespace rai
{
class block;
bool work_validate (rai::block_hash const &, uint64_t);
bool work_validate (rai::block const &);
uint64_t work_value (rai::block_hash const &, uint64_t);
class opencl_work;
class work_pool
{
public:
	work_pool (unsigned, std::function <boost::optional <uint64_t> (rai::uint256_union const &)> = nullptr);
	~work_pool ();
	void loop (uint64_t);
	void stop ();
	void cancel (rai::uint256_union const &);
	void generate (rai::uint256_union const &, std::function <void (boost::optional <uint64_t> const &)>);
	uint64_t generate (rai::uint256_union const &);
	std::atomic <int> ticket;
	bool done;
	std::vector <std::thread> threads;
	std::list <std::pair <rai::uint256_union, std::function <void (boost::optional <uint64_t> const &)>>> pending;
	std::mutex mutex;
	std::condition_variable producer_condition;
	std::function <boost::optional<uint64_t> (rai::uint256_union const &)> opencl;
	rai::observer_set <bool> work_observers;
	// Local work threshold for rate-limiting publishing blocks. ~5 seconds of work.
	static uint64_t const publish_test_threshold = 0xff00000000000000;
	static uint64_t const publish_full_threshold = 0xffffffc000000000;
	static uint64_t const publish_threshold = rai::rai_network == rai::rai_networks::rai_test_network ? publish_test_threshold : publish_full_threshold;
};
}

<|endoftext|>


<commit_before>#ifndef ORG_EEROS_CONTROL_CONSTANTACCTRAJECTORYGENERATOR_HPP_
#define ORG_EEROS_CONTROL_CONSTANTACCTRAJECTORYGENERATOR_HPP_

#include <eeros/core/EEROSException.hpp>
#include <cmath>
#include <mutex>
#include "TrajectoryGenerator.hpp"

namespace eeros {
	namespace control {

		template<typename T>
		class ConstantAccTrajectoryGenerator : public TrajectoryGenerator<T, 3> {

		public:

			using E = typename T::value_type;

			ConstantAccTrajectoryGenerator(T velMax, T accMax, T decMax, double dt) : finish(true), velMax(velMax), accMax(accMax), decMax(decMax), dt(dt) { }

			virtual bool finished() {
				std::lock_guard<std::mutex> lck(mtx);
				return finish;
			}

			virtual std::array<T, 3> get(double dt) {
				std::lock_guard<std::mutex> lck(mtx);
				std::array<T, 3> y = this->last;
				t += dt;

				for(unsigned int i = 0; i < a1p.size(); i++) {
					if(!finish) {
						if(t >= 0 && t < dT1) {
							y[0][i] = a1p[i] * pow(t, 2) + c1p[i];
							y[1][i] = b1v[i] * t;
							y[2][i] = c1a[i];
						}
						else if(t >= dT1 && t < dT1 + dT2) {
							y[0][i] = b2p[i] * t + c2p[i];
							y[1][i] = c2v[i];
							y[2][i] = 0;
						}
						else if(t >= dT1 + dT2 && t < dT1 + dT2 + dT3) {
							y[0][i] = a3p[i] * pow(t, 2) + b3p[i] * t + c3p[i];
							y[1][i] = b3v[i] * t + c3v[i];
							y[2][i] = c3a[i];
						}
						else if(t >= dT1 + dT2 + dT3) {
							finish = true;
							y[0][i] = this->last[0][i];
							y[1][i] = 0.0;
							y[2][i] = 0.0;
						}
						else { // t < 0
							throw EEROSException("get() failed, t < 0");
						}
					}
					// set last value
					this->last[0][i] = y[0][i];
					this->last[1][i] = y[1][i];
					this->last[2][i] = y[2][i];
				}

				return y;
			}

			virtual bool push(std::array<T, 3> start, std::array<T, 3> end) {
				if(!finish) return false;
				T calcVelNorm, calcAccNorm, calcDecNorm;
				E velNorm, accNorm, decNorm, squareNormVel;
				T distance = end[0] - start[0];

				T zero;
				zero = 0;
				if (distance == zero)
					return false;

				// Define speeds and accelerations
				for(unsigned int i = 0; i < calcVelNorm.size(); i++) {
					calcVelNorm[i] = fabs(velMax[i] / distance[i]);
					calcAccNorm[i] = fabs(accMax[i] / distance[i]);
					calcDecNorm[i] = fabs(decMax[i] / distance[i]);
				}

				// Init velNorm, accNorm, decNorm and find minimum
				velNorm = calcVelNorm[0]; accNorm = calcAccNorm[0]; decNorm = calcDecNorm[0];
				for(unsigned int i = 0; i < calcVelNorm.size(); i++) {
					if(calcVelNorm[i] < velNorm) velNorm = calcVelNorm[i];
					if(calcAccNorm[i] < accNorm) accNorm = calcAccNorm[i];
					if(calcDecNorm[i] < decNorm) decNorm = calcDecNorm[i];
				}

				// Minimize velocity
				squareNormVel = sqrt(2 * (accNorm * decNorm) / (accNorm + decNorm));
				if(velNorm > squareNormVel) velNorm = squareNormVel;

				// Calculate time intervals
				dT1 = velNorm / accNorm;
				dT3 = velNorm / decNorm;
				dT2 = 1 / velNorm - (dT1 + dT3) * 0.5;
				if (dT2 < 0) dT2 = 0;

				// Adaptation to timestamps
				dT1 = ceil(dT1 / dt) * dt;
				dT2 = ceil(dT2 / dt) * dt;
				dT3 = ceil(dT3 / dt) * dt;
				// Adaptation of speed to new timestamps
				velNorm = 1/((dT2 + (dT1 + dT3)*0.5)*dt);

				a1p = 0.5 * velNorm / dT1 * distance * dt;
				c1p = start[0];
				b1v = velNorm / dT1 * dt * distance * dt;
				c1a = velNorm * dt / dT1 * distance * pow(dt, 2);

				b2p = velNorm * dt * distance;
				c2p = start[0] - 0.5 * velNorm * dT1 * dt * distance;
				c2v = velNorm * distance * dt * dt;
				c2a = 0;

				a3p = (-1) * velNorm * 0.5 * dt / dT3 * distance;
				b3p = velNorm * dt / dT3 * (dT1 + dT2 + dT3) * distance;
				c3p = start[0] + (1 - velNorm * 0.5 * dt / dT3 * pow(dT1 + dT2 + dT3, 2)) * distance;
				b3v = (-1) *velNorm * dt * distance / dT3 * dt;
				c3v = velNorm * (dT1 + dT2 + dT3) * distance * dt / dT3 * dt;
				c3a = (-1) * velNorm * dt / dT3 * distance * dt * dt;

				std::lock_guard<std::mutex> lck(mtx);
				finish = false;
				t = 0;

				return true;
			}

			virtual void reset(std::array<T, 3> last) {
				std::lock_guard<std::mutex> lck(mtx);
				this->last = last;
				this->finish = true;
			}

		protected:
			std::mutex mtx;
			double dt;
			T velMax, accMax, decMax;

			double dT1, dT2, dT3;
			T a1p, c1p, b1v, c1a, b2p, c2p, c2v, c2a, a3p, b3p, c3p, b3v, c3v, c3a;

			double t;
			bool finish;
		};
	};
};

#endif /* ORG_EEROS_CONTROL_CONSTANTACCTRAJECTORYGENERATOR_HPP_ */

<commit_msg>fix includes of ConstantAccTrajectoryGenerator<commit_after>#ifndef ORG_EEROS_CONTROL_CONSTANTACCTRAJECTORYGENERATOR_HPP_
#define ORG_EEROS_CONTROL_CONSTANTACCTRAJECTORYGENERATOR_HPP_

#include <cmath>
#include <mutex>
#include <eeros/core/EEROSException.hpp>
#include <eeros/control/TrajectoryGenerator.hpp>

namespace eeros {
	namespace control {

		template<typename T>
		class ConstantAccTrajectoryGenerator : public TrajectoryGenerator<T, 3> {

		public:

			using E = typename T::value_type;

			ConstantAccTrajectoryGenerator(T velMax, T accMax, T decMax, double dt) : finish(true), velMax(velMax), accMax(accMax), decMax(decMax), dt(dt) { }

			virtual bool finished() {
				std::lock_guard<std::mutex> lck(mtx);
				return finish;
			}

			virtual std::array<T, 3> get(double dt) {
				std::lock_guard<std::mutex> lck(mtx);
				std::array<T, 3> y = this->last;
				t += dt;

				for(unsigned int i = 0; i < a1p.size(); i++) {
					if(!finish) {
						if(t >= 0 && t < dT1) {
							y[0][i] = a1p[i] * pow(t, 2) + c1p[i];
							y[1][i] = b1v[i] * t;
							y[2][i] = c1a[i];
						}
						else if(t >= dT1 && t < dT1 + dT2) {
							y[0][i] = b2p[i] * t + c2p[i];
							y[1][i] = c2v[i];
							y[2][i] = 0;
						}
						else if(t >= dT1 + dT2 && t < dT1 + dT2 + dT3) {
							y[0][i] = a3p[i] * pow(t, 2) + b3p[i] * t + c3p[i];
							y[1][i] = b3v[i] * t + c3v[i];
							y[2][i] = c3a[i];
						}
						else if(t >= dT1 + dT2 + dT3) {
							finish = true;
							y[0][i] = this->last[0][i];
							y[1][i] = 0.0;
							y[2][i] = 0.0;
						}
						else { // t < 0
							throw EEROSException("get() failed, t < 0");
						}
					}
					// set last value
					this->last[0][i] = y[0][i];
					this->last[1][i] = y[1][i];
					this->last[2][i] = y[2][i];
				}

				return y;
			}

			virtual bool push(std::array<T, 3> start, std::array<T, 3> end) {
				if(!finish) return false;
				T calcVelNorm, calcAccNorm, calcDecNorm;
				E velNorm, accNorm, decNorm, squareNormVel;
				T distance = end[0] - start[0];

				T zero;
				zero = 0;
				if (distance == zero)
					return false;

				// Define speeds and accelerations
				for(unsigned int i = 0; i < calcVelNorm.size(); i++) {
					calcVelNorm[i] = fabs(velMax[i] / distance[i]);
					calcAccNorm[i] = fabs(accMax[i] / distance[i]);
					calcDecNorm[i] = fabs(decMax[i] / distance[i]);
				}

				// Init velNorm, accNorm, decNorm and find minimum
				velNorm = calcVelNorm[0]; accNorm = calcAccNorm[0]; decNorm = calcDecNorm[0];
				for(unsigned int i = 0; i < calcVelNorm.size(); i++) {
					if(calcVelNorm[i] < velNorm) velNorm = calcVelNorm[i];
					if(calcAccNorm[i] < accNorm) accNorm = calcAccNorm[i];
					if(calcDecNorm[i] < decNorm) decNorm = calcDecNorm[i];
				}

				// Minimize velocity
				squareNormVel = sqrt(2 * (accNorm * decNorm) / (accNorm + decNorm));
				if(velNorm > squareNormVel) velNorm = squareNormVel;

				// Calculate time intervals
				dT1 = velNorm / accNorm;
				dT3 = velNorm / decNorm;
				dT2 = 1 / velNorm - (dT1 + dT3) * 0.5;
				if (dT2 < 0) dT2 = 0;

				// Adaptation to timestamps
				dT1 = ceil(dT1 / dt) * dt;
				dT2 = ceil(dT2 / dt) * dt;
				dT3 = ceil(dT3 / dt) * dt;
				// Adaptation of speed to new timestamps
				velNorm = 1/((dT2 + (dT1 + dT3)*0.5)*dt);

				a1p = 0.5 * velNorm / dT1 * distance * dt;
				c1p = start[0];
				b1v = velNorm / dT1 * dt * distance * dt;
				c1a = velNorm * dt / dT1 * distance * pow(dt, 2);

				b2p = velNorm * dt * distance;
				c2p = start[0] - 0.5 * velNorm * dT1 * dt * distance;
				c2v = velNorm * distance * dt * dt;
				c2a = 0;

				a3p = (-1) * velNorm * 0.5 * dt / dT3 * distance;
				b3p = velNorm * dt / dT3 * (dT1 + dT2 + dT3) * distance;
				c3p = start[0] + (1 - velNorm * 0.5 * dt / dT3 * pow(dT1 + dT2 + dT3, 2)) * distance;
				b3v = (-1) *velNorm * dt * distance / dT3 * dt;
				c3v = velNorm * (dT1 + dT2 + dT3) * distance * dt / dT3 * dt;
				c3a = (-1) * velNorm * dt / dT3 * distance * dt * dt;

				std::lock_guard<std::mutex> lck(mtx);
				finish = false;
				t = 0;

				return true;
			}

			virtual void reset(std::array<T, 3> last) {
				std::lock_guard<std::mutex> lck(mtx);
				this->last = last;
				this->finish = true;
			}

		protected:
			std::mutex mtx;
			double dt;
			T velMax, accMax, decMax;

			double dT1, dT2, dT3;
			T a1p, c1p, b1v, c1a, b2p, c2p, c2v, c2a, a3p, b3p, c3p, b3v, c3v, c3a;

			double t;
			bool finish;
		};
	};
};

#endif /* ORG_EEROS_CONTROL_CONSTANTACCTRAJECTORYGENERATOR_HPP_ */

<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////

#include "MMFilesSynchronizerThread.h"

#include "Basics/ConditionLocker.h"
#include "Basics/Exceptions.h"
#include "Basics/memory-map.h"
#include "Logger/Logger.h"
#include "StorageEngine/MMFilesWalSlots.h"
#include "StorageEngine/MMFilesWalSyncRegion.h"
#include "VocBase/ticks.h"
#include "Wal/LogfileManager.h"

using namespace arangodb;

/// @brief returns the bitmask for the synchronous waiters
/// for use in _waiters only
static constexpr inline uint64_t syncWaitersMask() {
  return static_cast<uint64_t>(0xffffffffULL);
}

/// @brief returns the numbers of bits to shift to get the
/// number of asynchronous waiters
/// for use in _waiters only
static constexpr inline int asyncWaitersBits() { return 32; }

MMFilesSynchronizerThread::MMFilesSynchronizerThread(wal::LogfileManager* logfileManager,
                                       uint64_t syncInterval)
    : Thread("WalSynchronizer"),
      _logfileManager(logfileManager),
      _condition(),
      _syncInterval(syncInterval),
      _logfileCache({0, -1}),
      _waiting(0) {}

/// @brief begin shutdown sequence
void MMFilesSynchronizerThread::beginShutdown() {
  Thread::beginShutdown();

  CONDITION_LOCKER(guard, _condition);
  guard.signal();
}

/// @brief signal that we need a sync
void MMFilesSynchronizerThread::signalSync(bool waitForSync) {
  if (waitForSync) {
    uint64_t previous = _waiting.fetch_add(1);
    if ((previous & syncWaitersMask()) == 0) {
      // only signal once, but don't care if we signal a bit too often
      CONDITION_LOCKER(guard, _condition);
      _condition.signal();
    }
  } else {
    uint64_t updateValue = 1ULL << asyncWaitersBits();
    _waiting.fetch_add(updateValue);
  }
}

/// @brief main loop
void MMFilesSynchronizerThread::run() {
  // fetch initial value for waiting
  uint64_t waitingValue = _waiting;
  uint64_t waitingWithoutSync = waitingValue >> asyncWaitersBits();
  uint64_t waitingWithSync = (waitingValue & syncWaitersMask());

  uint64_t iterations = 0;
  while (true) {
    if (waitingWithoutSync > 0 || waitingWithSync > 0 || ++iterations == 10) {
      iterations = 0;

      try {
        // sync as much as we can in this loop
        bool checkMore = false;

        while (true) {
          int res = doSync(checkMore);

          if (res != TRI_ERROR_NO_ERROR || !checkMore) {
            break;
          }
        }
      } catch (arangodb::basics::Exception const& ex) {
        int res = ex.code();
        LOG(ERR) << "got unexpected error in synchronizerThread: "
                 << TRI_errno_string(res);
      } catch (...) {
        LOG(ERR) << "got unspecific error in synchronizerThread";
      }
    }

    // update value of waiting
    uint64_t updateValue = waitingWithSync + (waitingWithoutSync << asyncWaitersBits());

    if (updateValue > 0) {
      // subtract and fetch previous value in one atomic operation
      waitingValue = _waiting.fetch_sub(updateValue);
      waitingValue -= updateValue; // subtract from previous value
    } else {
      // re-fetch current value
      waitingValue = _waiting;
    }

    waitingWithoutSync = waitingValue >> asyncWaitersBits();
    waitingWithSync = (waitingValue & syncWaitersMask());

    // now wait until we are woken up or there is something to do

    if (waitingWithSync == 0) {
      if (isStopping()) {
        // stop requested and all synced, we can exit
        break;
      }

      // sleep if nothing to do
      CONDITION_LOCKER(guard, _condition);
      guard.wait(_syncInterval);
    }
  }
}

/// @brief synchronize an unsynchronized region
int MMFilesSynchronizerThread::doSync(bool& checkMore) {
  checkMore = false;

  // get region to sync
  MMFilesWalSyncRegion region = _logfileManager->slots()->getSyncRegion();
  wal::Logfile::IdType const id = region.logfileId;

  // an id of 0 means an empty region...
  if (id == 0) {
    return TRI_ERROR_NO_ERROR;
  }

  // now perform the actual syncing
  auto status = region.logfileStatus;
  TRI_ASSERT(status == wal::Logfile::StatusType::OPEN ||
             status == wal::Logfile::StatusType::SEAL_REQUESTED);

  // get the logfile's file descriptor
  int fd = getLogfileDescriptor(region.logfileId);
  TRI_ASSERT(fd >= 0);

  bool result = TRI_MSync(fd, region.mem, region.mem + region.size);

  LOG(TRACE) << "syncing logfile " << id << ", region " << (void*) region.mem << " - "
             << (void*)(region.mem + region.size) << ", length: " << region.size
             << ", wfs: " << (region.waitForSync ? "true" : "false");

  if (!result) {
    LOG(ERR) << "unable to sync wal logfile region";

    return TRI_ERROR_ARANGO_MSYNC_FAILED;
  }

  // all ok

  if (status == wal::Logfile::StatusType::SEAL_REQUESTED) {
    // we might not yet be able to seal the logfile yet, for example in
    // the following situation when multi-threading:
    //
    //   // borrow 3 slots from the logfile manager
    //   auto slot1 = logfileManager->allocate(1);
    //   auto slot2 = logfileManager->allocate(1);
    //   auto slot3 = logfileManager->allocate(1);
    //
    //   // return slot 3
    //   logfileManager->finalize(slot3, false);
    //   // return slot 1
    //   logfileManager->finalize(slot1, false);
    //
    //   // some thread now requests flushing logs. this will produce a
    //   // sync region from slot 1..slot 1.
    //   logfileManager->flush(false, false, false);
    //
    //   // if we now return slot2, it would produce a sync region from
    //   // slot2..slot3. this is fine but won't work if the logfile is
    //   // already sealed.
    //   logfileManager->finalize(slot2, false);

    if (region.canSeal) {
      // only seal the logfile if it is safe to do so
      _logfileManager->setLogfileSealed(id);
    }
  }

  checkMore = region.checkMore;

  _logfileManager->slots()->returnSyncRegion(region);
  return TRI_ERROR_NO_ERROR;
}

/// @brief get a logfile descriptor (it caches the descriptor for performance)
int MMFilesSynchronizerThread::getLogfileDescriptor(wal::Logfile::IdType id) {
  if (id != _logfileCache.id || _logfileCache.id == 0) {
    _logfileCache.id = id;
    _logfileCache.fd = _logfileManager->getLogfileDescriptor(id);
  }

  return _logfileCache.fd;
}
<commit_msg>Debug log if an msync takes too long.<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2016 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////

#include "MMFilesSynchronizerThread.h"

#include "Basics/ConditionLocker.h"
#include "Basics/Exceptions.h"
#include "Basics/memory-map.h"
#include "Logger/Logger.h"
#include "StorageEngine/MMFilesWalSlots.h"
#include "StorageEngine/MMFilesWalSyncRegion.h"
#include "VocBase/ticks.h"
#include "Wal/LogfileManager.h"

using namespace arangodb;

/// @brief returns the bitmask for the synchronous waiters
/// for use in _waiters only
static constexpr inline uint64_t syncWaitersMask() {
  return static_cast<uint64_t>(0xffffffffULL);
}

/// @brief returns the numbers of bits to shift to get the
/// number of asynchronous waiters
/// for use in _waiters only
static constexpr inline int asyncWaitersBits() { return 32; }

MMFilesSynchronizerThread::MMFilesSynchronizerThread(wal::LogfileManager* logfileManager,
                                       uint64_t syncInterval)
    : Thread("WalSynchronizer"),
      _logfileManager(logfileManager),
      _condition(),
      _syncInterval(syncInterval),
      _logfileCache({0, -1}),
      _waiting(0) {}

/// @brief begin shutdown sequence
void MMFilesSynchronizerThread::beginShutdown() {
  Thread::beginShutdown();

  CONDITION_LOCKER(guard, _condition);
  guard.signal();
}

/// @brief signal that we need a sync
void MMFilesSynchronizerThread::signalSync(bool waitForSync) {
  if (waitForSync) {
    uint64_t previous = _waiting.fetch_add(1);
    if ((previous & syncWaitersMask()) == 0) {
      // only signal once, but don't care if we signal a bit too often
      CONDITION_LOCKER(guard, _condition);
      _condition.signal();
    }
  } else {
    uint64_t updateValue = 1ULL << asyncWaitersBits();
    _waiting.fetch_add(updateValue);
  }
}

/// @brief main loop
void MMFilesSynchronizerThread::run() {
  // fetch initial value for waiting
  uint64_t waitingValue = _waiting;
  uint64_t waitingWithoutSync = waitingValue >> asyncWaitersBits();
  uint64_t waitingWithSync = (waitingValue & syncWaitersMask());

  uint64_t iterations = 0;
  while (true) {
    if (waitingWithoutSync > 0 || waitingWithSync > 0 || ++iterations == 10) {
      iterations = 0;

      try {
        // sync as much as we can in this loop
        bool checkMore = false;

        while (true) {
          int res = doSync(checkMore);

          if (res != TRI_ERROR_NO_ERROR || !checkMore) {
            break;
          }
        }
      } catch (arangodb::basics::Exception const& ex) {
        int res = ex.code();
        LOG(ERR) << "got unexpected error in synchronizerThread: "
                 << TRI_errno_string(res);
      } catch (...) {
        LOG(ERR) << "got unspecific error in synchronizerThread";
      }
    }

    // update value of waiting
    uint64_t updateValue = waitingWithSync + (waitingWithoutSync << asyncWaitersBits());

    if (updateValue > 0) {
      // subtract and fetch previous value in one atomic operation
      waitingValue = _waiting.fetch_sub(updateValue);
      waitingValue -= updateValue; // subtract from previous value
    } else {
      // re-fetch current value
      waitingValue = _waiting;
    }

    waitingWithoutSync = waitingValue >> asyncWaitersBits();
    waitingWithSync = (waitingValue & syncWaitersMask());

    // now wait until we are woken up or there is something to do

    if (waitingWithSync == 0) {
      if (isStopping()) {
        // stop requested and all synced, we can exit
        break;
      }

      // sleep if nothing to do
      CONDITION_LOCKER(guard, _condition);
      guard.wait(_syncInterval);
    }
  }
}

/// @brief synchronize an unsynchronized region
int MMFilesSynchronizerThread::doSync(bool& checkMore) {
  checkMore = false;

  // get region to sync
  MMFilesWalSyncRegion region = _logfileManager->slots()->getSyncRegion();
  wal::Logfile::IdType const id = region.logfileId;

  // an id of 0 means an empty region...
  if (id == 0) {
    return TRI_ERROR_NO_ERROR;
  }

  // now perform the actual syncing
  auto status = region.logfileStatus;
  TRI_ASSERT(status == wal::Logfile::StatusType::OPEN ||
             status == wal::Logfile::StatusType::SEAL_REQUESTED);

  // get the logfile's file descriptor
  int fd = getLogfileDescriptor(region.logfileId);
  TRI_ASSERT(fd >= 0);

  double startTime = TRI_microtime();
  bool result = TRI_MSync(fd, region.mem, region.mem + region.size);
  if (TRI_microtime() - startTime > 1.0) {
    LOG(DEBUG) << "Long sync logfile " << id << ", region "
      << (void*) region.mem << ", size " << region.size;
  }

  LOG(TRACE) << "syncing logfile " << id << ", region " << (void*) region.mem << " - "
             << (void*)(region.mem + region.size) << ", length: " << region.size
             << ", wfs: " << (region.waitForSync ? "true" : "false");

  if (!result) {
    LOG(ERR) << "unable to sync wal logfile region";

    return TRI_ERROR_ARANGO_MSYNC_FAILED;
  }

  // all ok

  if (status == wal::Logfile::StatusType::SEAL_REQUESTED) {
    // we might not yet be able to seal the logfile yet, for example in
    // the following situation when multi-threading:
    //
    //   // borrow 3 slots from the logfile manager
    //   auto slot1 = logfileManager->allocate(1);
    //   auto slot2 = logfileManager->allocate(1);
    //   auto slot3 = logfileManager->allocate(1);
    //
    //   // return slot 3
    //   logfileManager->finalize(slot3, false);
    //   // return slot 1
    //   logfileManager->finalize(slot1, false);
    //
    //   // some thread now requests flushing logs. this will produce a
    //   // sync region from slot 1..slot 1.
    //   logfileManager->flush(false, false, false);
    //
    //   // if we now return slot2, it would produce a sync region from
    //   // slot2..slot3. this is fine but won't work if the logfile is
    //   // already sealed.
    //   logfileManager->finalize(slot2, false);

    if (region.canSeal) {
      // only seal the logfile if it is safe to do so
      _logfileManager->setLogfileSealed(id);
    }
  }

  checkMore = region.checkMore;

  _logfileManager->slots()->returnSyncRegion(region);
  return TRI_ERROR_NO_ERROR;
}

/// @brief get a logfile descriptor (it caches the descriptor for performance)
int MMFilesSynchronizerThread::getLogfileDescriptor(wal::Logfile::IdType id) {
  if (id != _logfileCache.id || _logfileCache.id == 0) {
    _logfileCache.id = id;
    _logfileCache.fd = _logfileManager->getLogfileDescriptor(id);
  }

  return _logfileCache.fd;
}
<|endoftext|>