<commit_before>

// Persistent RNN Includes
#include <persistent_rnn_high_level.h>

#include <prnn/detail/matrix/matrix.h>
#include <prnn/detail/matrix/random_operations.h>
#include <prnn/detail/matrix/matrix_operations.h>
#include <prnn/detail/matrix/matrix_transforms.h>
#include <prnn/detail/matrix/copy_operations.h>
#include <prnn/detail/matrix/operation.h>

#include <prnn/detail/rnn/recurrent_ops_handle.h>
#include <prnn/detail/rnn/recurrent_ops.h>

#include <prnn/detail/util/logger.h>
#include <prnn/detail/util/argument_parser.h>

// Standard Library Includes
#include <random>
#include <iostream>

class Options
{
public:
    size_t layerSize;
    size_t miniBatchSize;
    size_t timesteps;

public:
    size_t gradientCheckSamples;

public:
    prnn::RecurrentLayerDirection direction;

public:
    bool verbose;

};

void TestSimpleRecurrentOps(const Options& options)
{
    auto precision = prnn::matrix::SinglePrecision();

    prnn::matrix::srand(377);

    size_t layer_size = options.layerSize;
    size_t timesteps  = options.timesteps;
    size_t mini_batch = options.miniBatchSize;

    prnn::RecurrentOpsHandle handle(layer_size, mini_batch, timesteps,
        prnn::RecurrentRectifiedLinear(), options.direction);

    auto weights     = ones({layer_size, layer_size}, precision);
    auto activations = ones({layer_size, mini_batch, timesteps}, precision);

    forwardPropRecurrent(activations, weights, handle);

    auto deltas = ones(activations.size(), precision);

    backPropDeltasRecurrent(deltas, weights, activations, handle);

    auto dWeights = ones(weights.size(), precision);

    backPropGradientsRecurrent(dWeights, activations, deltas, handle);

    // just make sure nothing crashes
}

void slice_window(prnn::matrix::Matrix& inputs, size_t window_size)
{
    size_t activation_count = inputs.size()[0];
    size_t mini_batch_size  = inputs.size()[1];
    size_t timesteps        = inputs.size()[2];

    size_t activation_size = std::min(window_size, activation_count);

    inputs = slice(inputs,
        {0,               0,               0},
        {activation_size, mini_batch_size, timesteps});
}

prnn::matrix::Matrix extract_window(prnn::matrix::Matrix inputs, size_t window_size)
{
    size_t activation_count = inputs.size()[0];
    size_t mini_batch_size  = inputs.size()[1];
    size_t timesteps        = inputs.size()[2];

    size_t activation_size = std::min(window_size, activation_count);

    auto sliced_inputs = slice(inputs,
        {0,               0,               0},
        {activation_size, mini_batch_size, timesteps});

    auto zeros = prnn::matrix::zeros(inputs.size(), inputs.precision());

    auto sliced_zeros = slice(zeros,
        {0,               0,               0},
        {activation_size, mini_batch_size, timesteps});

    copy(sliced_zeros, sliced_inputs);

    return zeros;
}

double compute_cost(prnn::matrix::Matrix activations, prnn::matrix::Matrix reference,
    size_t window_size)
{
    slice_window(activations, window_size);
    slice_window(reference,   window_size);

    auto difference = apply(prnn::matrix::Matrix(activations),
        reference, prnn::matrix::Subtract());
    auto squaredDifference = apply(difference, prnn::matrix::Square());

    double squaredSum = reduce(squaredDifference, {}, prnn::matrix::Add())[0];

    return 0.5 * squaredSum / activations.size()[1];
}

prnn::matrix::Matrix compute_deltas(prnn::matrix::Matrix complete_activations,
    prnn::matrix::Matrix complete_reference, size_t window_size)
{
    auto activations = extract_window(complete_activations, window_size);
    auto reference   = extract_window(complete_reference,   window_size);

    size_t mini_batch = activations.size()[1];

    return apply(apply(prnn::matrix::Matrix(activations), reference, prnn::matrix::Subtract()),
        prnn::matrix::Multiply(1.0 / mini_batch));
}

void assertLessThanOrEqual(double left, double right)
{
    if(left <= right)
    {
        std::stringstream stream;

        stream << "Assertion Failed (" << left << " <= " << right << ")\n";

        throw std::logic_error(stream.str());
    }
}

void assertGreaterThanOrEqual(double left, double right)
{
    if(left >= right)
    {
        std::stringstream stream;

        stream << "Assertion Failed (" << left << " <= " << right << ")\n";

        throw std::logic_error(stream.str());
    }
}

void TestSimpleRecurrentOpsGradientCheck(const Options& options)
{
    auto precision = prnn::matrix::SinglePrecision();

    std::default_random_engine random_engine;

    random_engine.seed(377);

    prnn::matrix::srand(377);

    size_t layer_size = options.layerSize;
    size_t timesteps  = options.timesteps;
    size_t mini_batch = options.miniBatchSize;
    size_t samples    = options.gradientCheckSamples;

    size_t window_rows    = layer_size;
    size_t window_columns = window_rows;
    size_t window_outputs = window_rows;

    samples = std::min(window_rows * window_columns, samples);

    prnn::RecurrentOpsHandle handle(layer_size, mini_batch, timesteps,
        prnn::RecurrentRectifiedLinear(), options.direction, true, 0.5);

    auto weights = zeros({layer_size, layer_size}, precision);
    auto weights_slice = slice(weights, {0, 0}, {window_rows, window_columns});

    copy(weights_slice, rand({window_rows, window_columns}, precision));

    apply(weights, weights, prnn::matrix::Multiply(1.0e-2));

    auto input_activations = zeros({layer_size, mini_batch, timesteps}, precision);

    auto reference_activations = zeros({layer_size, mini_batch, timesteps}, precision);

    copy(
        slice(input_activations,
                     {0, 0, 0},
                     {window_outputs, mini_batch, timesteps}),
        rand({window_outputs, mini_batch, timesteps}, precision));

    copy(
        slice(reference_activations,
                    {0, 0, 0},
                    {window_outputs, mini_batch, timesteps}),
        rand({window_outputs, mini_batch, timesteps}, precision));

    auto output_activations = copy(input_activations);

    prnn::util::log("TestRecurrent") << "Input Weights     " << weights.debugString();
    prnn::util::log("TestRecurrent") << "Input Activations " <<
        reshape(copy(slice(output_activations,
                             {0,0,0},
                             {window_outputs, mini_batch, timesteps})),
            {window_outputs, mini_batch * timesteps}).debugString();

    forwardPropRecurrent(output_activations, weights, handle);

    prnn::util::log("TestRecurrent") << "Output Activations " <<
        reshape(copy(slice(output_activations,
                           {0,0,0},
                           {window_outputs, mini_batch, timesteps})),
            {window_outputs, mini_batch * timesteps}).debugString();

    prnn::util::log("TestRecurrent") << "Reference Activations " <<
        reshape(copy(slice(reference_activations,
                           {0,0,0},
                           {window_outputs, mini_batch, timesteps})),
            {window_outputs, mini_batch * timesteps}).debugString();

    double cost = compute_cost  (output_activations, reference_activations, window_outputs);
    auto deltas = compute_deltas(output_activations, reference_activations, window_outputs);

    prnn::util::log("TestRecurrent") << "Input Deltas " <<
        reshape(copy(slice(deltas,
                           {0,0,0},
                           {window_outputs, mini_batch, timesteps})),
            {window_outputs, mini_batch * timesteps}).debugString();

    backPropDeltasRecurrent(deltas, weights, output_activations, handle);

    auto dWeights = ones(weights.size(), precision);

    backPropGradientsRecurrent(dWeights, output_activations, deltas, handle);

    prnn::util::log("TestRecurrent") << "Output Deltas " <<
        reshape(copy(slice(deltas,
                           {0,0,0},
                           {window_outputs, mini_batch, timesteps})),
            {window_outputs, mini_batch * timesteps}).debugString();
    prnn::util::log("TestRecurrent") << "dWeights      " << dWeights.debugString();

    size_t gradient_count = window_rows * window_columns;

    std::vector<size_t> sample_positions = {0, 5};

    while (sample_positions.size() < samples) {
        sample_positions.push_back(random_engine() % gradient_count);
    }

    // grad check over the sample positions
    double epsilon    = 1.0e-4;
    double difference = 0.0;
    double total      = 0.0;

    for (auto& sample_position : sample_positions) {

        size_t sample_row    = sample_position % window_rows;
        size_t sample_column = sample_position / window_rows;

        double original_value = weights (sample_row, sample_column);
        double gradient       = dWeights(sample_row, sample_column);

        weights(sample_row, sample_column) = original_value - epsilon;

        prnn::util::log("TestRecurrent") << "Updated Input Weight (" << sample_row << ", "
            << sample_column << ")     from " << original_value << " to "
            << (original_value - epsilon) << "\n";

        auto copied_output_activations = copy(input_activations);
        forwardPropRecurrent(copied_output_activations, weights, handle);

        prnn::util::log("TestRecurrent") << "Updated Output Activations " <<
            reshape(copy(slice(copied_output_activations,
                                     {0,0,0},
                                     {window_outputs, mini_batch, timesteps})),
                           {window_outputs, mini_batch * timesteps}).debugString();

        double left_cost = compute_cost(copied_output_activations, reference_activations,
            window_outputs);

        weights(sample_row, sample_column) = original_value + epsilon;

        prnn::util::log("TestRecurrent") << "Updated Input Weight (" << sample_row << ", "
            << sample_column << ")     from " << original_value << " to "
            << (original_value + epsilon) << "\n";

        copied_output_activations = copy(input_activations);

        forwardPropRecurrent(copied_output_activations, weights, handle);
        prnn::util::log("TestRecurrent") << "Updated Output Activations " <<
            reshape(copy(slice(copied_output_activations,
                               {0,0,0},
                               {window_outputs, mini_batch, timesteps})),
                   {window_outputs, mini_batch * timesteps}).debugString();

        double right_cost = compute_cost(copied_output_activations, reference_activations,
            window_outputs);

        weights(sample_row, sample_column) = original_value;

        double numerical_gradient = (right_cost - left_cost) / (2.0 * epsilon);
        double local_difference = numerical_gradient - gradient;

        difference += std::pow(local_difference, 2.0);

        double absolute_difference = (local_difference == 0 || gradient == 0) ?
            0.0 : std::abs(local_difference) / std::abs(gradient);

        total += std::pow(gradient, 2.0);

        double scaled_difference = (total == 0.0) ? difference : (difference / total);

        if (absolute_difference > 1e-3 || !std::isfinite(local_difference))
        {
            prnn::util::log("TestRecurrent") << "For weight (" << sample_row << ", "
                << sample_column
                << ") computed gradient " << gradient << " does not match estimated gradient "
                << numerical_gradient << ", cost " << cost << " left cost "
                << left_cost << ", right cost " << right_cost <<  ", " << local_difference
                << " difference, " << scaled_difference<< " scaled difference\n";
        }
        else
        {
            prnn::util::log("TestRecurrent") << "For weight (" << sample_row << ", "
                << sample_column
                << ") computed gradient " << gradient << " matches estimated gradient "
                << numerical_gradient << "\n";
        }
    }

    difference = (difference == 0.0 && total == 0.0) ? 0.0 : (difference / total);

    assertGreaterThanOrEqual(difference, 3e-2 );
    assertLessThanOrEqual(   difference, 1e-16);
}

void TestRecurrentOpsGradientCheck(const Options& options)
{
    Options newOptions = options;

    newOptions.direction = prnn::RECURRENT_FORWARD;

    TestRecurrentOpsGradientCheck(newOptions);
}

void TestReverseRecurrentOpsGradientCheck(const Options& options)
{
    Options newOptions = options;

    newOptions.direction = prnn::RECURRENT_FORWARD;

    TestRecurrentOpsGradientCheck(newOptions);
}

void RunTest(const std::string& testName, void (*function)(const Options& options),
    const Options& options)
{
    try
    {
        function(options);
        std::cout << "Test '" << testName << "' Passed\n";
    }
    catch(std::exception& e)
    {
        std::cout << "Test '" << testName << "' Failed with error '" << e.what() << "'\n";
    }
}

int main(int argc, char** argv)
{
    prnn::util::ArgumentParser parser(argc, argv);

    auto precision = prnn::matrix::SinglePrecision();

    Options options;

    options.layerSize = prnn::rnn::getMaximumSizeRNNForThisGPU(precision);
    options.timesteps = 10;
    options.verbose   = false;

    parser.parse("-t", "--timeteps",   options.timesteps,     options.timesteps,     "The number of timesteps to run the RNN for.");
    parser.parse("-b", "--mini-batch", options.miniBatchSize, options.miniBatchSize, "The mini-batch size to run through the layer.");
    parser.parse("-l", "--layer-size", options.layerSize,     options.layerSize,     "The size of the RNN layer to operate on.");

    parser.parse("-s", "--grad-check-samples", options.gradientCheckSamples,
        options.gradientCheckSamples, "The number of weights to perform gradient check on.");

    parser.parse("-v", "--verbose", options.verbose, options.verbose, "Enable all PRNN logs.");

    parser.parse();

    prnn::util::enable_all_logs();

    RunTest("Recurrent Forward Ops Gradient Check", TestRecurrentOpsGradientCheck       , options);
    //RunTest("Recurrent Reverse Ops Gradient Check", TestReverseRecurrentOpsGradientCheck, options);
    RunTest("Simple Recurrent Ops Test",            TestSimpleRecurrentOps              , options);

    return 0;
}

<commit_msg>ENH: More config options on grad check.<commit_after>

// Persistent RNN Includes
#include <persistent_rnn_high_level.h>

#include <prnn/detail/matrix/matrix.h>
#include <prnn/detail/matrix/random_operations.h>
#include <prnn/detail/matrix/matrix_operations.h>
#include <prnn/detail/matrix/matrix_transforms.h>
#include <prnn/detail/matrix/copy_operations.h>
#include <prnn/detail/matrix/operation.h>

#include <prnn/detail/rnn/recurrent_ops_handle.h>
#include <prnn/detail/rnn/recurrent_ops.h>

#include <prnn/detail/util/logger.h>
#include <prnn/detail/util/argument_parser.h>

// Standard Library Includes
#include <random>
#include <iostream>

class Options
{
public:
    size_t layerSize;
    size_t miniBatchSize;
    size_t timesteps;

public:
    size_t gradientCheckSamples;

public:
    prnn::RecurrentLayerDirection direction;

public:
    bool verbose;

};

void TestSimpleRecurrentOps(const Options& options)
{
    auto precision = prnn::matrix::SinglePrecision();

    prnn::matrix::srand(377);

    size_t layer_size = options.layerSize;
    size_t timesteps  = options.timesteps;
    size_t mini_batch = options.miniBatchSize;

    prnn::RecurrentOpsHandle handle(layer_size, mini_batch, timesteps,
        prnn::RecurrentRectifiedLinear(), options.direction);

    auto weights     = ones({layer_size, layer_size}, precision);
    auto activations = ones({layer_size, mini_batch, timesteps}, precision);

    forwardPropRecurrent(activations, weights, handle);

    auto deltas = ones(activations.size(), precision);

    backPropDeltasRecurrent(deltas, weights, activations, handle);

    auto dWeights = ones(weights.size(), precision);

    backPropGradientsRecurrent(dWeights, activations, deltas, handle);

    // just make sure nothing crashes
}

void slice_window(prnn::matrix::Matrix& inputs, size_t window_size)
{
    size_t activation_count = inputs.size()[0];
    size_t mini_batch_size  = inputs.size()[1];
    size_t timesteps        = inputs.size()[2];

    size_t activation_size = std::min(window_size, activation_count);

    inputs = slice(inputs,
        {0,               0,               0},
        {activation_size, mini_batch_size, timesteps});
}

prnn::matrix::Matrix extract_window(prnn::matrix::Matrix inputs, size_t window_size)
{
    size_t activation_count = inputs.size()[0];
    size_t mini_batch_size  = inputs.size()[1];
    size_t timesteps        = inputs.size()[2];

    size_t activation_size = std::min(window_size, activation_count);

    auto sliced_inputs = slice(inputs,
        {0,               0,               0},
        {activation_size, mini_batch_size, timesteps});

    auto zeros = prnn::matrix::zeros(inputs.size(), inputs.precision());

    auto sliced_zeros = slice(zeros,
        {0,               0,               0},
        {activation_size, mini_batch_size, timesteps});

    copy(sliced_zeros, sliced_inputs);

    return zeros;
}

double compute_cost(prnn::matrix::Matrix activations, prnn::matrix::Matrix reference,
    size_t window_size)
{
    slice_window(activations, window_size);
    slice_window(reference,   window_size);

    auto difference = apply(prnn::matrix::Matrix(activations),
        reference, prnn::matrix::Subtract());
    auto squaredDifference = apply(difference, prnn::matrix::Square());

    double squaredSum = reduce(squaredDifference, {}, prnn::matrix::Add())[0];

    return 0.5 * squaredSum / activations.size()[1];
}

prnn::matrix::Matrix compute_deltas(prnn::matrix::Matrix complete_activations,
    prnn::matrix::Matrix complete_reference, size_t window_size)
{
    auto activations = extract_window(complete_activations, window_size);
    auto reference   = extract_window(complete_reference,   window_size);

    size_t mini_batch = activations.size()[1];

    return apply(apply(prnn::matrix::Matrix(activations), reference, prnn::matrix::Subtract()),
        prnn::matrix::Multiply(1.0 / mini_batch));
}

void assertLessThanOrEqual(double left, double right)
{
    if(left <= right)
    {
        std::stringstream stream;

        stream << "Assertion Failed (" << left << " <= " << right << ")\n";

        throw std::logic_error(stream.str());
    }
}

void assertGreaterThanOrEqual(double left, double right)
{
    if(left >= right)
    {
        std::stringstream stream;

        stream << "Assertion Failed (" << left << " <= " << right << ")\n";

        throw std::logic_error(stream.str());
    }
}

void TestSimpleRecurrentOpsGradientCheck(const Options& options)
{
    auto precision = prnn::matrix::SinglePrecision();

    std::default_random_engine random_engine;

    random_engine.seed(377);

    prnn::matrix::srand(377);

    size_t layer_size = options.layerSize;
    size_t timesteps  = options.timesteps;
    size_t mini_batch = options.miniBatchSize;
    size_t samples    = options.gradientCheckSamples;

    size_t window_rows    = layer_size;
    size_t window_columns = window_rows;
    size_t window_outputs = window_rows;

    samples = std::min(window_rows * window_columns, samples);

    prnn::RecurrentOpsHandle handle(layer_size, mini_batch, timesteps,
        prnn::RecurrentRectifiedLinear(), options.direction, true, 0.5);

    auto weights = zeros({layer_size, layer_size}, precision);
    auto weights_slice = slice(weights, {0, 0}, {window_rows, window_columns});

    copy(weights_slice, rand({window_rows, window_columns}, precision));

    apply(weights, weights, prnn::matrix::Multiply(1.0e-2));

    auto input_activations = zeros({layer_size, mini_batch, timesteps}, precision);

    auto reference_activations = zeros({layer_size, mini_batch, timesteps}, precision);

    copy(
        slice(input_activations,
                     {0, 0, 0},
                     {window_outputs, mini_batch, timesteps}),
        rand({window_outputs, mini_batch, timesteps}, precision));

    copy(
        slice(reference_activations,
                    {0, 0, 0},
                    {window_outputs, mini_batch, timesteps}),
        rand({window_outputs, mini_batch, timesteps}, precision));

    auto output_activations = copy(input_activations);

    prnn::util::log("TestRecurrent") << "Input Weights     " << weights.debugString();
    prnn::util::log("TestRecurrent") << "Input Activations " <<
        reshape(copy(slice(output_activations,
                             {0,0,0},
                             {window_outputs, mini_batch, timesteps})),
            {window_outputs, mini_batch * timesteps}).debugString();

    forwardPropRecurrent(output_activations, weights, handle);

    prnn::util::log("TestRecurrent") << "Output Activations " <<
        reshape(copy(slice(output_activations,
                           {0,0,0},
                           {window_outputs, mini_batch, timesteps})),
            {window_outputs, mini_batch * timesteps}).debugString();

    prnn::util::log("TestRecurrent") << "Reference Activations " <<
        reshape(copy(slice(reference_activations,
                           {0,0,0},
                           {window_outputs, mini_batch, timesteps})),
            {window_outputs, mini_batch * timesteps}).debugString();

    double cost = compute_cost  (output_activations, reference_activations, window_outputs);
    auto deltas = compute_deltas(output_activations, reference_activations, window_outputs);

    prnn::util::log("TestRecurrent") << "Input Deltas " <<
        reshape(copy(slice(deltas,
                           {0,0,0},
                           {window_outputs, mini_batch, timesteps})),
            {window_outputs, mini_batch * timesteps}).debugString();

    backPropDeltasRecurrent(deltas, weights, output_activations, handle);

    auto dWeights = ones(weights.size(), precision);

    backPropGradientsRecurrent(dWeights, output_activations, deltas, handle);

    prnn::util::log("TestRecurrent") << "Output Deltas " <<
        reshape(copy(slice(deltas,
                           {0,0,0},
                           {window_outputs, mini_batch, timesteps})),
            {window_outputs, mini_batch * timesteps}).debugString();
    prnn::util::log("TestRecurrent") << "dWeights      " << dWeights.debugString();

    size_t gradient_count = window_rows * window_columns;

    std::vector<size_t> sample_positions = {0, 5};

    while (sample_positions.size() < samples) {
        sample_positions.push_back(random_engine() % gradient_count);
    }

    // grad check over the sample positions
    double epsilon    = 1.0e-4;
    double difference = 0.0;
    double total      = 0.0;

    for (auto& sample_position : sample_positions) {

        size_t sample_row    = sample_position % window_rows;
        size_t sample_column = sample_position / window_rows;

        double original_value = weights (sample_row, sample_column);
        double gradient       = dWeights(sample_row, sample_column);

        weights(sample_row, sample_column) = original_value - epsilon;

        prnn::util::log("TestRecurrent") << "Updated Input Weight (" << sample_row << ", "
            << sample_column << ")     from " << original_value << " to "
            << (original_value - epsilon) << "\n";

        auto copied_output_activations = copy(input_activations);
        forwardPropRecurrent(copied_output_activations, weights, handle);

        prnn::util::log("TestRecurrent") << "Updated Output Activations " <<
            reshape(copy(slice(copied_output_activations,
                                     {0,0,0},
                                     {window_outputs, mini_batch, timesteps})),
                           {window_outputs, mini_batch * timesteps}).debugString();

        double left_cost = compute_cost(copied_output_activations, reference_activations,
            window_outputs);

        weights(sample_row, sample_column) = original_value + epsilon;

        prnn::util::log("TestRecurrent") << "Updated Input Weight (" << sample_row << ", "
            << sample_column << ")     from " << original_value << " to "
            << (original_value + epsilon) << "\n";

        copied_output_activations = copy(input_activations);

        forwardPropRecurrent(copied_output_activations, weights, handle);
        prnn::util::log("TestRecurrent") << "Updated Output Activations " <<
            reshape(copy(slice(copied_output_activations,
                               {0,0,0},
                               {window_outputs, mini_batch, timesteps})),
                   {window_outputs, mini_batch * timesteps}).debugString();

        double right_cost = compute_cost(copied_output_activations, reference_activations,
            window_outputs);

        weights(sample_row, sample_column) = original_value;

        double numerical_gradient = (right_cost - left_cost) / (2.0 * epsilon);
        double local_difference = numerical_gradient - gradient;

        difference += std::pow(local_difference, 2.0);

        double absolute_difference = (local_difference == 0 || gradient == 0) ?
            0.0 : std::abs(local_difference) / std::abs(gradient);

        total += std::pow(gradient, 2.0);

        double scaled_difference = (total == 0.0) ? difference : (difference / total);

        if (absolute_difference > 1e-3 || !std::isfinite(local_difference))
        {
            prnn::util::log("TestRecurrent") << "For weight (" << sample_row << ", "
                << sample_column
                << ") computed gradient " << gradient << " does not match estimated gradient "
                << numerical_gradient << ", cost " << cost << " left cost "
                << left_cost << ", right cost " << right_cost <<  ", " << local_difference
                << " difference, " << scaled_difference<< " scaled difference\n";
        }
        else
        {
            prnn::util::log("TestRecurrent") << "For weight (" << sample_row << ", "
                << sample_column
                << ") computed gradient " << gradient << " matches estimated gradient "
                << numerical_gradient << "\n";
        }
    }

    difference = (difference == 0.0 && total == 0.0) ? 0.0 : (difference / total);

    assertGreaterThanOrEqual(difference, 3e-2 );
    assertLessThanOrEqual(   difference, 1e-16);
}

void TestRecurrentOpsGradientCheck(const Options& options)
{
    Options newOptions = options;

    newOptions.direction = prnn::RECURRENT_FORWARD;

    TestSimpleRecurrentOpsGradientCheck(newOptions);
}

void TestReverseRecurrentOpsGradientCheck(const Options& options)
{
    Options newOptions = options;

    newOptions.direction = prnn::RECURRENT_FORWARD;

    TestSimpleRecurrentOpsGradientCheck(newOptions);
}

void RunTest(const std::string& testName, void (*function)(const Options& options),
    const Options& options)
{
    try
    {
        function(options);
        std::cout << "Test '" << testName << "' Passed\n";
    }
    catch(std::exception& e)
    {
        std::cout << "Test '" << testName << "' Failed with error '" << e.what() << "'\n";
    }
}

int main(int argc, char** argv)
{
    prnn::util::ArgumentParser parser(argc, argv);

    auto precision = prnn::matrix::SinglePrecision();

    Options options;

    options.layerSize = prnn::rnn::getMaximumSizeRNNForThisGPU(precision);
    options.timesteps = 10;
    options.verbose   = false;

    options.miniBatchSize = 3;
    options.gradientCheckSamples = 32;

    parser.parse("-t", "--timeteps",   options.timesteps,     options.timesteps,     "The number of timesteps to run the RNN for.");
    parser.parse("-b", "--mini-batch", options.miniBatchSize, options.miniBatchSize, "The mini-batch size to run through the layer.");
    parser.parse("-l", "--layer-size", options.layerSize,     options.layerSize,     "The size of the RNN layer to operate on.");

    parser.parse("-s", "--grad-check-samples", options.gradientCheckSamples,
        options.gradientCheckSamples, "The number of weights to perform gradient check on.");

    parser.parse("-v", "--verbose", options.verbose, options.verbose, "Enable all PRNN logs.");

    parser.parse();

    prnn::util::enable_all_logs();

    RunTest("Recurrent Forward Ops Gradient Check", TestRecurrentOpsGradientCheck       , options);
    //RunTest("Recurrent Reverse Ops Gradient Check", TestReverseRecurrentOpsGradientCheck, options);
    RunTest("Simple Recurrent Ops Test",            TestSimpleRecurrentOps              , options);

    return 0;
}

<|endoftext|>


<commit_before>#ifndef _TRANSPORT_HPP_
#define _TRANSPORT_HPP_

/* Solve a transportation problem with given costs, supply and demand.
 *
 * costs is an array of size sizeSupply*sizeDemand, indexed by edge (i,j) at
 * entry i*sizeDemand+j
 *
 * supply is array of size sizeSupply
 * demand is array of size sizeDemand
 *
 * flow is output array of same size/indexing as costs
 *
 * Must have sum of supplies = sum of demands
 */
template <typename T>
void solveTransport(int sizeSupply, int sizeDemand, const T* costs,
        const T* supply, const T* demand, T* flow);

#endif
<commit_msg>Comments on transport.hpp<commit_after>#ifndef _TRANSPORT_HPP_
#define _TRANSPORT_HPP_

/* Solve a transportation problem with given costs, supply and demand.
 *
 * min \sum_{i,j} c_{i,j} x_{i,j}
 * s.t. \sum_j x_{i,j} = s_i
 *      \sum_i x_{i,j} = d_j
 *      x_{i,j} <= 0
 *
 * costs is an array of size sizeSupply*sizeDemand, indexed by edge (i,j) at
 * entry i*sizeDemand+j
 *
 * supply is array of size sizeSupply
 * demand is array of size sizeDemand
 *
 * flow is output array of same size/indexing as costs
 *
 * Must have sum of supplies = sum of demands
 */
template <typename T>
void solveTransport(int sizeSupply, int sizeDemand, const T* costs,
        const T* supply, const T* demand, T* flow);

#endif
<|endoftext|>


<commit_before>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2016                                                               *
 *                                                                                *
 * 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 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.                                         *
 ****************************************************************************************/

#include <openspace/util/time.h>

#include <time.h>

#include "time_lua.inl"

#include <openspace/util/spicemanager.h>
#include <openspace/util/syncbuffer.h>

#include <ghoul/filesystem/filesystem.h>
#include <ghoul/misc/assert.h>

namespace openspace {

Time* Time::_instance = nullptr;

Time::Time(double secondsJ2000)
    : _time(secondsJ2000)
    , _dt(1.0)
    //local copies
    , _timeJumped(false)
    , _timePaused(false)
    , _jockeHasToFixThisLater(false)
    //shared copies
    , _sharedTime(-1.0)
    , _sharedDt(1.0)
    , _sharedTimeJumped(false)
    //synced copies
    , _syncedTime(-1.0)
    , _syncedDt(1.0)
    , _syncedTimeJumped(false)
{

}

Time::Time(const Time& other)
    : _time(other._time)
    , _dt(other._dt)
    //local copies
    , _timeJumped(other._timeJumped)
    , _timePaused(other._timePaused)
    , _jockeHasToFixThisLater(other._jockeHasToFixThisLater)
    //shared copies
    , _sharedTime(other._sharedTime)
    , _sharedDt(other._sharedDt)
    , _sharedTimeJumped(other._sharedTimeJumped)
    //synced copies
    , _syncedTime(other._syncedTime)
    , _syncedDt(other._syncedDt)
    , _syncedTimeJumped(other._syncedTimeJumped)
{

}

void Time::initialize() {
    ghoul_assert(_instance == nullptr, "Static time must not have been ininitialized");
    _instance = new Time();
}

void Time::deinitialize() {
    ghoul_assert(_instance, "Static time must have been ininitialized");
    delete _instance;
    _instance = nullptr;
}

Time& Time::ref() {
    ghoul_assert(_instance, "Static time must have been ininitialized");
    return *_instance;
}

Time Time::now() {
    Time now;
    time_t secondsSince1970;
    secondsSince1970 = time(nullptr);
    time_t secondsInAYear = 365.25 * 24 * 60 * 60;
    double secondsSince2000 = (double)(secondsSince1970 - 30*secondsInAYear);
    now.setTime(secondsSince2000);
    return now;
}

bool Time::isInitialized() {
    return (_instance != nullptr);
}

void Time::setTime(double value, bool requireJump) {
    _time = value;
    _timeJumped = requireJump;
}

double Time::currentTime() const {
    return _syncedTime;
}

double Time::unsyncedJ2000Seconds() const {
    return _time;
}

double Time::advanceTime(double tickTime) {
    if (_timePaused)
        return _time;
    else
        return _time += _dt * tickTime;
}

void Time::setDeltaTime(double deltaT) {
    _dt = deltaT;
}

double Time::deltaTime() const {
    return _syncedDt;
}

void Time::setPause(bool pause) {
    _timePaused = pause;
}

bool Time::togglePause() {
    _timePaused = !_timePaused;
    return _timePaused;
}

void Time::setTime(std::string time, bool requireJump) {
    _time = SpiceManager::ref().ephemerisTimeFromDate(std::move(time));
    _timeJumped = requireJump;
}

std::string Time::currentTimeUTC() const {
    return SpiceManager::ref().dateFromEphemerisTime(_syncedTime);
}

std::string Time::ISO8601() const {
    std::string datetime = SpiceManager::ref().dateFromEphemerisTime(_time);
    std::string month = datetime.substr(5, 3);

    std::string MM = "";
    if (month == "JAN") MM = "01";
    else if (month == "FEB") MM = "02";
    else if (month == "MAR") MM = "03";
    else if (month == "APR") MM = "04";
    else if (month == "MAY") MM = "05";
    else if (month == "JUN") MM = "06";
    else if (month == "JUL") MM = "07";
    else if (month == "AUG") MM = "08";
    else if (month == "SEP") MM = "09";
    else if (month == "OCT") MM = "10";
    else if (month == "NOV") MM = "11";
    else if (month == "DEC") MM = "12";
    else ghoul_assert(false, "Bad month");

    datetime.replace(4, 5, "-" + MM + "-");
    return datetime;
}

void Time::serialize(SyncBuffer* syncBuffer) {
    _syncMutex.lock();

    syncBuffer->encode(_sharedTime);
    syncBuffer->encode(_sharedDt);
    syncBuffer->encode(_sharedTimeJumped);

    _syncMutex.unlock();
}

void Time::deserialize(SyncBuffer* syncBuffer) {
    _syncMutex.lock();

    syncBuffer->decode(_sharedTime);
    syncBuffer->decode(_sharedDt);
    syncBuffer->decode(_sharedTimeJumped);

    if (_sharedTimeJumped)
        _jockeHasToFixThisLater = true;

    _syncMutex.unlock();
}

void Time::postSynchronizationPreDraw() {
    _syncMutex.lock();

    _syncedTime = _sharedTime;
    _syncedDt = _sharedDt;
    _syncedTimeJumped = _sharedTimeJumped;

    if (_jockeHasToFixThisLater) {
        _syncedTimeJumped = true;
        _jockeHasToFixThisLater = false;
    }

    _syncMutex.unlock();
}

void Time::preSynchronization() {
    _syncMutex.lock();

    _sharedTime = _time;
    _sharedDt = _dt;
    _sharedTimeJumped = _timeJumped;

    _syncMutex.unlock();
}

bool Time::timeJumped() const {
    return _syncedTimeJumped;
}

void Time::setTimeJumped(bool jumped) {
    _timeJumped = jumped;
}

bool Time::paused() const {
    return _timePaused;
}

scripting::ScriptEngine::LuaLibrary Time::luaLibrary() {
    scripting::ScriptEngine::LuaLibrary timeLibrary = {
        "time",
        {
            {
                "setDeltaTime",
                &luascriptfunctions::time_setDeltaTime,
                "number",
                "Sets the amount of simulation time that happens "
                "in one second of real time",
                true
            },
            {
                "deltaTime",
                &luascriptfunctions::time_deltaTime,
                "",
                "Returns the amount of simulated time that passes in one "
                "second of real time"
            },
            {
                "setPause",
                &luascriptfunctions::time_setPause,
                "bool",
                "Pauses the simulation time or restores the delta time",
                true
            },
            {
                "togglePause",
                &luascriptfunctions::time_togglePause,
                "",
                "Toggles the pause function, i.e. temporarily setting the delta time to 0"
                " and restoring it afterwards",
                true
            },
            {
                "setTime",
                &luascriptfunctions::time_setTime,
                "{number, string}",
                "Sets the current simulation time to the "
                "specified value. If the parameter is a number, the value is the number "
                "of seconds past the J2000 epoch. If it is a string, it has to be a "
                "valid ISO 8601 date string (YYYY-MM-DDTHH:MN:SS)",
                true
            },
            {
                "currentTime",
                &luascriptfunctions::time_currentTime,
                "",
                "Returns the current time as the number of seconds since "
                "the J2000 epoch"
            },
            {
                "currentTimeUTC",
                &luascriptfunctions::time_currentTimeUTC,
                "",
                "Returns the current time as an ISO 8601 date string "
                "(YYYY-MM-DDTHH:MN:SS)"
            },
            {
                "currentWallTime",
                &luascriptfunctions::time_currentWallTime,
                "",
                "Returns the current wall time as an ISO 8601 date string "
                "(YYYY-MM-DDTHH-MN-SS) in the UTC timezone"
            }
        }
    };
    return timeLibrary;
}

} // namespace openspace
<commit_msg>Solve synching bug in time class.<commit_after>/*****************************************************************************************
 *                                                                                *
 * OpenSpace                                                                             *
 *                                                                                *
 * Copyright (c) 2014-2016                                                               *
 *                                                                                *
 * 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 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.                                         *
 ****************************************************************************************/

#include <openspace/util/time.h>

#include <time.h>

#include "time_lua.inl"

#include <openspace/util/spicemanager.h>
#include <openspace/util/syncbuffer.h>

#include <ghoul/filesystem/filesystem.h>
#include <ghoul/misc/assert.h>

namespace openspace {

Time* Time::_instance = nullptr;

Time::Time(double secondsJ2000)
    : _time(secondsJ2000)
    , _dt(1.0)
    //local copies
    , _timeJumped(false)
    , _timePaused(false)
    , _jockeHasToFixThisLater(false)
    //shared copies
    , _sharedTime(-1.0)
    , _sharedDt(1.0)
    , _sharedTimeJumped(false)
    //synced copies
    , _syncedTime(-1.0)
    , _syncedDt(1.0)
    , _syncedTimeJumped(false)
{

}

Time::Time(const Time& other)
    : _time(other._time)
    , _dt(other._dt)
    //local copies
    , _timeJumped(other._timeJumped)
    , _timePaused(other._timePaused)
    , _jockeHasToFixThisLater(other._jockeHasToFixThisLater)
    //shared copies
    , _sharedTime(other._sharedTime)
    , _sharedDt(other._sharedDt)
    , _sharedTimeJumped(other._sharedTimeJumped)
    //synced copies
    , _syncedTime(other._syncedTime)
    , _syncedDt(other._syncedDt)
    , _syncedTimeJumped(other._syncedTimeJumped)
{

}

void Time::initialize() {
    ghoul_assert(_instance == nullptr, "Static time must not have been ininitialized");
    _instance = new Time();
}

void Time::deinitialize() {
    ghoul_assert(_instance, "Static time must have been ininitialized");
    delete _instance;
    _instance = nullptr;
}

Time& Time::ref() {
    ghoul_assert(_instance, "Static time must have been ininitialized");
    return *_instance;
}

Time Time::now() {
    Time now;
    time_t secondsSince1970;
    secondsSince1970 = time(nullptr);
    time_t secondsInAYear = 365.25 * 24 * 60 * 60;
    double secondsSince2000 = (double)(secondsSince1970 - 30*secondsInAYear);
    now.setTime(secondsSince2000);
    return now;
}

bool Time::isInitialized() {
    return (_instance != nullptr);
}

void Time::setTime(double value, bool requireJump) {
    _time = value;
    _timeJumped = requireJump;
}

double Time::currentTime() const {
    return _syncedTime;
}

double Time::unsyncedJ2000Seconds() const {
    return _time;
}

double Time::advanceTime(double tickTime) {
    if (_timePaused)
        return _time;
    else
        return _time += _dt * tickTime;
}

void Time::setDeltaTime(double deltaT) {
    _dt = deltaT;
}

double Time::deltaTime() const {
    return _syncedDt;
}

void Time::setPause(bool pause) {
    _timePaused = pause;
}

bool Time::togglePause() {
    _timePaused = !_timePaused;
    return _timePaused;
}

void Time::setTime(std::string time, bool requireJump) {
    _time = SpiceManager::ref().ephemerisTimeFromDate(std::move(time));
    _timeJumped = requireJump;
}

std::string Time::currentTimeUTC() const {
    return SpiceManager::ref().dateFromEphemerisTime(_syncedTime);
}

std::string Time::ISO8601() const {
    std::string datetime = SpiceManager::ref().dateFromEphemerisTime(_syncedTime);
    std::string month = datetime.substr(5, 3);

    std::string MM = "";
    if (month == "JAN") MM = "01";
    else if (month == "FEB") MM = "02";
    else if (month == "MAR") MM = "03";
    else if (month == "APR") MM = "04";
    else if (month == "MAY") MM = "05";
    else if (month == "JUN") MM = "06";
    else if (month == "JUL") MM = "07";
    else if (month == "AUG") MM = "08";
    else if (month == "SEP") MM = "09";
    else if (month == "OCT") MM = "10";
    else if (month == "NOV") MM = "11";
    else if (month == "DEC") MM = "12";
    else ghoul_assert(false, "Bad month");

    datetime.replace(4, 5, "-" + MM + "-");
    return datetime;
}

void Time::serialize(SyncBuffer* syncBuffer) {
    _syncMutex.lock();

    syncBuffer->encode(_sharedTime);
    syncBuffer->encode(_sharedDt);
    syncBuffer->encode(_sharedTimeJumped);

    _syncMutex.unlock();
}

void Time::deserialize(SyncBuffer* syncBuffer) {
    _syncMutex.lock();

    syncBuffer->decode(_sharedTime);
    syncBuffer->decode(_sharedDt);
    syncBuffer->decode(_sharedTimeJumped);

    if (_sharedTimeJumped)
        _jockeHasToFixThisLater = true;

    _syncMutex.unlock();
}

void Time::postSynchronizationPreDraw() {
    _syncMutex.lock();

    _syncedTime = _sharedTime;
    _syncedDt = _sharedDt;
    _syncedTimeJumped = _sharedTimeJumped;

    if (_jockeHasToFixThisLater) {
        _syncedTimeJumped = true;
        _jockeHasToFixThisLater = false;
    }

    _syncMutex.unlock();
}

void Time::preSynchronization() {
    _syncMutex.lock();

    _sharedTime = _time;
    _sharedDt = _dt;
    _sharedTimeJumped = _timeJumped;

    _syncMutex.unlock();
}

bool Time::timeJumped() const {
    return _syncedTimeJumped;
}

void Time::setTimeJumped(bool jumped) {
    _timeJumped = jumped;
}

bool Time::paused() const {
    return _timePaused;
}

scripting::ScriptEngine::LuaLibrary Time::luaLibrary() {
    scripting::ScriptEngine::LuaLibrary timeLibrary = {
        "time",
        {
            {
                "setDeltaTime",
                &luascriptfunctions::time_setDeltaTime,
                "number",
                "Sets the amount of simulation time that happens "
                "in one second of real time",
                true
            },
            {
                "deltaTime",
                &luascriptfunctions::time_deltaTime,
                "",
                "Returns the amount of simulated time that passes in one "
                "second of real time"
            },
            {
                "setPause",
                &luascriptfunctions::time_setPause,
                "bool",
                "Pauses the simulation time or restores the delta time",
                true
            },
            {
                "togglePause",
                &luascriptfunctions::time_togglePause,
                "",
                "Toggles the pause function, i.e. temporarily setting the delta time to 0"
                " and restoring it afterwards",
                true
            },
            {
                "setTime",
                &luascriptfunctions::time_setTime,
                "{number, string}",
                "Sets the current simulation time to the "
                "specified value. If the parameter is a number, the value is the number "
                "of seconds past the J2000 epoch. If it is a string, it has to be a "
                "valid ISO 8601 date string (YYYY-MM-DDTHH:MN:SS)",
                true
            },
            {
                "currentTime",
                &luascriptfunctions::time_currentTime,
                "",
                "Returns the current time as the number of seconds since "
                "the J2000 epoch"
            },
            {
                "currentTimeUTC",
                &luascriptfunctions::time_currentTimeUTC,
                "",
                "Returns the current time as an ISO 8601 date string "
                "(YYYY-MM-DDTHH:MN:SS)"
            },
            {
                "currentWallTime",
                &luascriptfunctions::time_currentWallTime,
                "",
                "Returns the current wall time as an ISO 8601 date string "
                "(YYYY-MM-DDTHH-MN-SS) in the UTC timezone"
            }
        }
    };
    return timeLibrary;
}

} // namespace openspace
<|endoftext|>


<commit_before>#ifndef OPENCLGL_UTILITIES_H
#define OPENCLGL_UTILITIES_H

#if defined (__APPLE__) || defined(MACOSX)
   #define GL_SHARING_EXTENSION "cl_APPLE_gl_sharing"
#else
   #define GL_SHARING_EXTENSION "cl_khr_gl_sharing"
#endif

#include "openCLUtilities.hpp"

#if defined(__APPLE__) || defined(__MACOSX)
#include <OpenGL/OpenGL.h>
#else
#if _WIN32
#else
#include <GL/glx.h>
#endif
#endif

cl::Context createCLGLContext(cl_device_type type = CL_DEVICE_TYPE_ALL, cl_vendor vendor = VENDOR_ANY);

#endif
<commit_msg>added contribution by Jim Vaughn for selecting a SINGLE valid device for a CL-GL context<commit_after>#ifndef OPENCLGL_UTILITIES_H
#define OPENCLGL_UTILITIES_H

#if defined (__APPLE__) || defined(MACOSX)
   #define GL_SHARING_EXTENSION "cl_APPLE_gl_sharing"
#else
   #define GL_SHARING_EXTENSION "cl_khr_gl_sharing"
#endif

#include "openCLUtilities.hpp"
#include <CL/cl_gl.h>

#if defined(__APPLE__) || defined(__MACOSX)
#include <OpenGL/OpenGL.h>
#else
#if _WIN32
#else
#include <GL/glx.h>
#endif
#endif

cl::Context createCLGLContext(cl_device_type type = CL_DEVICE_TYPE_ALL, cl_vendor vendor = VENDOR_ANY);
cl::Device getValidGLCLInteropDevice(cl::Platform platform, cl_context_properties* properties);

#endif
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_pm_init.C $          */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016                             */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///
/// @file p9_pm_init.C
/// @brief Wrapper that initializes or resets the OCC complex.
///
// *HWP HWP Owner        : Greg Still <stillgs@us.ibm.com>
// *HWP HWP Backup Owner :
// *HWP FW Owner         : Sangeetha T S <sangeet2@in.ibm.com>
// *HWP Team             : PM
// *HWP Level            : 2
// *HWP Consumed by      : HS

///
/// High-level procedure flow:
///
/// @verbatim
///
///  PM_INIT
///    Initialize Cores and Quads
///    Initialize OCB channels
///    Initialize PSS
///    Initialize PBA
///    Mask CME FIRs and Core-Quad Errors
///    Initialize Stop GPE
///    Initialize Pstate GPE
///    Start OCC PPC405
///    Clear off pending Special Wakeup requests on all configured EX chiplets
///
///  PM_RESET
///    Invoke "p9_pm_reset()" to reset the PM OCC complex (Cores, Quads, CMEs,
///    OCB channels, PBA bus, PSS, PPC405 and GPEs)
///
/// @endverbatim
///

// -----------------------------------------------------------------------------
// Includes
// -----------------------------------------------------------------------------
#include <p9_pm_init.H>

// -----------------------------------------------------------------------------
// Function prototypes
// -----------------------------------------------------------------------------

///
/// @brief Call underlying unit procedures to initialize the PM complex.
///
/// @param[in] i_target Chip target
///
/// @return FAPI2_RC_SUCCESS on success, else error code.
///
fapi2::ReturnCode pm_init(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target);

///
/// @brief Clears OCC special wake-up on all configured EX chiplets
///
/// @param[in] i_target   Chip target
///
/// @return FAPI2_RC_SUCCESS on success, else error code.
///
fapi2::ReturnCode clear_occ_special_wakeups(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target);

// -----------------------------------------------------------------------------
// Function definitions
// -----------------------------------------------------------------------------

fapi2::ReturnCode p9_pm_init(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
    const p9pm::PM_FLOW_MODE i_mode)
{
    FAPI_INF("Entering p9_pm_init ...");

    fapi2::ReturnCode l_rc;

    if (i_mode == p9pm::PM_INIT)
    {
        FAPI_DBG("Initialize the OCC Complex.");
        FAPI_TRY(pm_init(i_target),
                 "ERROR: Failed to initialize OCC Complex");
    }
    else if (i_mode == p9pm::PM_RESET)
    {
        FAPI_DBG("Reset the OCC Complex.");
        FAPI_EXEC_HWP(l_rc, p9_pm_reset, i_target);
        FAPI_TRY(l_rc, "ERROR: Failed to reset OCC complex");
    }
    else
    {
        FAPI_ASSERT(false, fapi2::PM_INIT_BAD_MODE().set_BADMODE(i_mode),
                    "ERROR; Unknown mode passed to p9_pm_init. Mode %x",
                    i_mode);
    }

fapi_try_exit:
    FAPI_INF("Exiting p9_pm_init...");
    return fapi2::current_err;
}

fapi2::ReturnCode pm_init(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target)
{
    FAPI_INF("Entering pm_init...");

    fapi2::ReturnCode l_rc;

    //  ************************************************************************
    //  Initialize Cores and Quads
    //  ************************************************************************
    FAPI_DBG("Executing p9_pm_corequad_init to initialize cores & quads");
    FAPI_EXEC_HWP(l_rc, p9_pm_corequad_init,
                  i_target,
                  p9pm::PM_INIT,
                  0,//CME FIR MASK for reset
                  0,//Core Error Mask for reset
                  0 //Quad Error Mask for reset
                 );
    FAPI_TRY(l_rc, "ERROR: Failed to initialize cores & quads");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "After cores & quads init"));

    //  ************************************************************************
    //  Issue init to OCB
    //  ************************************************************************
    FAPI_DBG("Executing p9_pm_ocb_init to initialize OCB channels");
    FAPI_EXEC_HWP(l_rc, p9_pm_ocb_init,
                  i_target,
                  p9pm::PM_INIT,// Channel setup type
                  p9ocb::OCB_CHAN1,// Channel
                  p9ocb:: OCB_TYPE_NULL,// Channel type
                  0,// Channel base address
                  0,// Push/Pull queue length
                  p9ocb::OCB_Q_OUFLOW_NULL,// Channel flow control
                  p9ocb::OCB_Q_ITPTYPE_NULL// Channel interrupt control
                 );
    FAPI_TRY(l_rc,
             "ERROR: Failed to initialize channel 1");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "After OCB channels init"));

    //  ************************************************************************
    //  Initializes P2S and HWC logic
    //  ************************************************************************
    FAPI_DBG("Executing p9_pm_pss_init to initialize P2S and HWC logic");
    FAPI_EXEC_HWP(l_rc, p9_pm_pss_init, i_target, p9pm::PM_INIT);
    FAPI_TRY(l_rc, "ERROR: Failed to initialize PSS & HWC");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "After PSS & HWC init"));

    //  ************************************************************************
    //  Initializes PBA
    //  Note:  This voids the channel used by the GPEs
    //  ************************************************************************
    FAPI_DBG("Executing p9_pm_pba_init to initialize PBA");
    FAPI_EXEC_HWP(l_rc, p9_pm_pba_init, i_target, p9pm::PM_INIT);
    FAPI_TRY(l_rc, "ERROR: Failed to initialize PBA BUS");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "After PBA bus init"));

    //  ************************************************************************
    //  Mask the FIRs as errors can occur in what follows
    //  ************************************************************************
    FAPI_DBG("Executing p9_pm_firinit to mask errors/FIRs");
    FAPI_EXEC_HWP(l_rc, p9_pm_firinit, i_target, p9pm::PM_INIT);
    FAPI_TRY(l_rc, "ERROR: Failed to mask OCC,PBA & CME FIRs/Errors.");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "After masking FIRs and Errors"));

    //  ************************************************************************
    //  Initialize the STOP GPE Engine
    //  ************************************************************************
    FAPI_DBG("Executing p9_pm_stop_gpe_init to initialize SGPE");
    FAPI_EXEC_HWP(l_rc, p9_pm_stop_gpe_init, i_target, p9pm::PM_INIT);
    FAPI_TRY(l_rc, "ERROR: Failed to initialize SGPE");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "After SGPE initialization"));

    // ************************************************************************
    // Switch off OCC initiated special wakeup on EX to allowSTOP functionality
    // ************************************************************************
    FAPI_DBG("Clear off the wakeup");
    FAPI_TRY(clear_occ_special_wakeups(i_target),
             "ERROR: Failed to clear off the wakeup");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "EX targets off special wakeup"));

    //  ************************************************************************
    //  Initialize the PSTATE GPE Engine
    //  ************************************************************************
    /* TODO: RTC 157096: Enable pstate GPE initialization in PM_INIT phase
    FAPI_DBG("Executing p9_pm_pstate_gpe_init to initialize PGPE");
    FAPI_EXEC_HWP(l_rc, p9_pm_pstate_gpe_init, i_target, p9pm::PM_INIT);
    FAPI_TRY(l_rc, "ERROR: Failed to initialize PGPE");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "After PGPE initialization"));
    */

    //  ************************************************************************
    //  Start OCC PPC405
    //  ************************************************************************
    FAPI_DBG("Executing p9_pm_occ_control to start OCC PPC405");
    FAPI_EXEC_HWP(l_rc, p9_pm_occ_control, i_target,
                  p9occ_ctrl::PPC405_START,// Operation on PPC405
                  p9occ_ctrl::PPC405_BOOT_MEM // PPC405 boot location
                 );
    FAPI_TRY(l_rc, "ERROR: Failed to initialize OCC PPC405");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "After OCC PPC405 init"));

fapi_try_exit:

    return fapi2::current_err;

}

fapi2::ReturnCode clear_occ_special_wakeups(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target)
{
    FAPI_INF("Entering clear_occ_special_wakeups...");
    fapi2::buffer<uint64_t> l_data64;

    auto l_exChiplets = i_target.getChildren<fapi2::TARGET_TYPE_EX>
                        (fapi2::TARGET_STATE_FUNCTIONAL);

    FAPI_DBG("No. of functional EX chiplets: %u ", l_exChiplets.size());

    // Iterate through the EX chiplets
    for (auto l_ex_chplt : l_exChiplets)
    {
        FAPI_DBG("Clear OCC special wakeup on ex chiplet 0x%08X", l_ex_chplt);
        FAPI_TRY(fapi2::getScom(i_target, EX_PPM_SPWKUP_OCC, l_data64),
                 "ERROR: Failed to read OCC Spl wkup on EX 0x%08X", l_ex_chplt);
        l_data64.clearBit<0>();
        FAPI_TRY(fapi2::putScom(i_target, EX_PPM_SPWKUP_OCC, l_data64),
                 "ERROR: Failed to clear OCC Spl wkup on EX 0x%08X", l_ex_chplt);
    }

fapi_try_exit:
    return fapi2::current_err;
}

<commit_msg>Set engine lock to HOST before PPC405 start<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_pm_init.C $          */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016                             */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
///
/// @file p9_pm_init.C
/// @brief Wrapper that initializes or resets the OCC complex.
///
// *HWP HWP Owner        : Greg Still <stillgs@us.ibm.com>
// *HWP HWP Backup Owner :
// *HWP FW Owner         : Sangeetha T S <sangeet2@in.ibm.com>
// *HWP Team             : PM
// *HWP Level            : 2
// *HWP Consumed by      : HS

///
/// High-level procedure flow:
///
/// @verbatim
///
///  PM_INIT
///    Initialize Cores and Quads
///    Initialize OCB channels
///    Initialize PSS
///    Initialize PBA
///    Mask CME FIRs and Core-Quad Errors
///    Initialize Stop GPE
///    Initialize Pstate GPE
///    Start OCC PPC405
///    Clear off pending Special Wakeup requests on all configured EX chiplets
///
///  PM_RESET
///    Invoke "p9_pm_reset()" to reset the PM OCC complex (Cores, Quads, CMEs,
///    OCB channels, PBA bus, PSS, PPC405 and GPEs)
///
/// @endverbatim
///

// -----------------------------------------------------------------------------
// Includes
// -----------------------------------------------------------------------------
#include <p9_pm_init.H>

// -----------------------------------------------------------------------------
// Function prototypes
// -----------------------------------------------------------------------------

///
/// @brief Call underlying unit procedures to initialize the PM complex.
///
/// @param[in] i_target Chip target
///
/// @return FAPI2_RC_SUCCESS on success, else error code.
///
fapi2::ReturnCode pm_init(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target);

///
/// @brief Clears OCC special wake-up on all configured EX chiplets
///
/// @param[in] i_target   Chip target
///
/// @return FAPI2_RC_SUCCESS on success, else error code.
///
fapi2::ReturnCode clear_occ_special_wakeups(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target);

// -----------------------------------------------------------------------------
// Function definitions
// -----------------------------------------------------------------------------

fapi2::ReturnCode p9_pm_init(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target,
    const p9pm::PM_FLOW_MODE i_mode)
{
    FAPI_INF("Entering p9_pm_init ...");

    fapi2::ReturnCode l_rc;

    if (i_mode == p9pm::PM_INIT)
    {
        FAPI_DBG("Initialize the OCC Complex.");
        FAPI_TRY(pm_init(i_target),
                 "ERROR: Failed to initialize OCC Complex");
    }
    else if (i_mode == p9pm::PM_RESET)
    {
        FAPI_DBG("Reset the OCC Complex.");
        FAPI_EXEC_HWP(l_rc, p9_pm_reset, i_target);
        FAPI_TRY(l_rc, "ERROR: Failed to reset OCC complex");
    }
    else
    {
        FAPI_ASSERT(false, fapi2::PM_INIT_BAD_MODE().set_BADMODE(i_mode),
                    "ERROR; Unknown mode passed to p9_pm_init. Mode %x",
                    i_mode);
    }

fapi_try_exit:
    FAPI_INF("Exiting p9_pm_init...");
    return fapi2::current_err;
}

fapi2::ReturnCode pm_init(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target)
{
    FAPI_INF("Entering pm_init...");

    fapi2::ReturnCode l_rc;
    fapi2::buffer<uint64_t> l_data64;

    //  ************************************************************************
    //  Initialize Cores and Quads
    //  ************************************************************************
    FAPI_DBG("Executing p9_pm_corequad_init to initialize cores & quads");
    FAPI_EXEC_HWP(l_rc, p9_pm_corequad_init,
                  i_target,
                  p9pm::PM_INIT,
                  0,//CME FIR MASK for reset
                  0,//Core Error Mask for reset
                  0 //Quad Error Mask for reset
                 );
    FAPI_TRY(l_rc, "ERROR: Failed to initialize cores & quads");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "After cores & quads init"));

    //  ************************************************************************
    //  Issue init to OCB
    //  ************************************************************************
    FAPI_DBG("Executing p9_pm_ocb_init to initialize OCB channels");
    FAPI_EXEC_HWP(l_rc, p9_pm_ocb_init,
                  i_target,
                  p9pm::PM_INIT,// Channel setup type
                  p9ocb::OCB_CHAN1,// Channel
                  p9ocb:: OCB_TYPE_NULL,// Channel type
                  0,// Channel base address
                  0,// Push/Pull queue length
                  p9ocb::OCB_Q_OUFLOW_NULL,// Channel flow control
                  p9ocb::OCB_Q_ITPTYPE_NULL// Channel interrupt control
                 );
    FAPI_TRY(l_rc,
             "ERROR: Failed to initialize channel 1");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "After OCB channels init"));

    //  ************************************************************************
    //  Initializes P2S and HWC logic
    //  ************************************************************************
    FAPI_DBG("Executing p9_pm_pss_init to initialize P2S and HWC logic");
    FAPI_EXEC_HWP(l_rc, p9_pm_pss_init, i_target, p9pm::PM_INIT);
    FAPI_TRY(l_rc, "ERROR: Failed to initialize PSS & HWC");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "After PSS & HWC init"));

    //  ************************************************************************
    //  Initializes PBA
    //  Note:  This voids the channel used by the GPEs
    //  ************************************************************************
    FAPI_DBG("Executing p9_pm_pba_init to initialize PBA");
    FAPI_EXEC_HWP(l_rc, p9_pm_pba_init, i_target, p9pm::PM_INIT);
    FAPI_TRY(l_rc, "ERROR: Failed to initialize PBA BUS");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "After PBA bus init"));

    //  ************************************************************************
    //  Mask the FIRs as errors can occur in what follows
    //  ************************************************************************
    FAPI_DBG("Executing p9_pm_firinit to mask errors/FIRs");
    FAPI_EXEC_HWP(l_rc, p9_pm_firinit, i_target, p9pm::PM_INIT);
    FAPI_TRY(l_rc, "ERROR: Failed to mask OCC,PBA & CME FIRs/Errors.");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "After masking FIRs and Errors"));

    //  ************************************************************************
    //  Initialize the STOP GPE Engine
    //  ************************************************************************
    FAPI_DBG("Executing p9_pm_stop_gpe_init to initialize SGPE");
    FAPI_EXEC_HWP(l_rc, p9_pm_stop_gpe_init, i_target, p9pm::PM_INIT);
    FAPI_TRY(l_rc, "ERROR: Failed to initialize SGPE");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "After SGPE initialization"));

    // ************************************************************************
    // Switch off OCC initiated special wakeup on EX to allowSTOP functionality
    // ************************************************************************
    FAPI_DBG("Clear off the wakeup");
    FAPI_TRY(clear_occ_special_wakeups(i_target),
             "ERROR: Failed to clear off the wakeup");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "EX targets off special wakeup"));

    //  ************************************************************************
    //  Initialize the PSTATE GPE Engine
    //  ************************************************************************
    /* TODO: RTC 157096: Enable pstate GPE initialization in PM_INIT phase
    FAPI_DBG("Executing p9_pm_pstate_gpe_init to initialize PGPE");
    FAPI_EXEC_HWP(l_rc, p9_pm_pstate_gpe_init, i_target, p9pm::PM_INIT);
    FAPI_TRY(l_rc, "ERROR: Failed to initialize PGPE");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "After PGPE initialization"));
    */

    // Clear the OCC's PIB I2C engine locks.
    // All other OCC owned flag bits are retained.
    l_data64.setBit<17>().setBit<19>().setBit<21>();
    FAPI_TRY(fapi2::putScom(i_target, PU_OCB_OCI_OCCFLG_SCOM1, l_data64),
             "ERROR: Failed to write to OCC FLAG");

    //  ************************************************************************
    //  Start OCC PPC405
    //  ************************************************************************
    FAPI_DBG("Executing p9_pm_occ_control to start OCC PPC405");
    FAPI_EXEC_HWP(l_rc, p9_pm_occ_control, i_target,
                  p9occ_ctrl::PPC405_START,// Operation on PPC405
                  p9occ_ctrl::PPC405_BOOT_MEM // PPC405 boot location
                 );
    FAPI_TRY(l_rc, "ERROR: Failed to initialize OCC PPC405");
    FAPI_TRY(p9_pm_glob_fir_trace(i_target, "After OCC PPC405 init"));

fapi_try_exit:

    return fapi2::current_err;

}

fapi2::ReturnCode clear_occ_special_wakeups(
    const fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target)
{
    FAPI_INF("Entering clear_occ_special_wakeups...");
    fapi2::buffer<uint64_t> l_data64;

    auto l_exChiplets = i_target.getChildren<fapi2::TARGET_TYPE_EX>
                        (fapi2::TARGET_STATE_FUNCTIONAL);

    FAPI_DBG("No. of functional EX chiplets: %u ", l_exChiplets.size());

    // Iterate through the EX chiplets
    for (auto l_ex_chplt : l_exChiplets)
    {
        FAPI_DBG("Clear OCC special wakeup on ex chiplet 0x%08X", l_ex_chplt);
        FAPI_TRY(fapi2::getScom(i_target, EX_PPM_SPWKUP_OCC, l_data64),
                 "ERROR: Failed to read OCC Spl wkup on EX 0x%08X", l_ex_chplt);
        l_data64.clearBit<0>();
        FAPI_TRY(fapi2::putScom(i_target, EX_PPM_SPWKUP_OCC, l_data64),
                 "ERROR: Failed to clear OCC Spl wkup on EX 0x%08X", l_ex_chplt);
    }

fapi_try_exit:
    return fapi2::current_err;
}

<|endoftext|>