<commit_before>// Copyright 2014 BVLC and contributors.

#include <algorithm>
#include <vector>

#include "cuda_runtime.h"
#include "gtest/gtest.h"

#include "caffe/blob.hpp"
#include "caffe/common.hpp"
#include "caffe/filler.hpp"
#include "caffe/vision_layers.hpp"
#include "caffe/test/test_gradient_check_util.hpp"

#include "caffe/test/test_caffe_main.hpp"

namespace caffe {

extern cudaDeviceProp CAFFE_TEST_CUDA_PROP;

template <typename Dtype>
class PowerLayerTest : public ::testing::Test {
 protected:
  PowerLayerTest()
      : blob_bottom_(new Blob<Dtype>(2, 3, 4, 5)),
        blob_top_(new Blob<Dtype>()) {
    // fill the values
    FillerParameter filler_param;
    GaussianFiller<Dtype> filler(filler_param);
    filler.Fill(this->blob_bottom_);
    blob_bottom_vec_.push_back(blob_bottom_);
    blob_top_vec_.push_back(blob_top_);
  }
  virtual ~PowerLayerTest() { delete blob_bottom_; delete blob_top_; }

  void TestForward(Dtype power, Dtype scale, Dtype shift) {
    LayerParameter layer_param;
    layer_param.mutable_power_param()->set_power(power);
    layer_param.mutable_power_param()->set_scale(scale);
    layer_param.mutable_power_param()->set_shift(shift);
    PowerLayer<Dtype> layer(layer_param);
    layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
    layer.Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
    // Now, check values
    const Dtype* bottom_data = this->blob_bottom_->cpu_data();
    const Dtype* top_data = this->blob_top_->cpu_data();
    const Dtype min_precision = 1e-5;
    for (int i = 0; i < this->blob_bottom_->count(); ++i) {
      Dtype expected_value = pow(shift + scale * bottom_data[i], power);
      if (power == Dtype(0) || power == Dtype(1) || power == Dtype(2)) {
        EXPECT_FALSE(isnan(top_data[i]));
      }
      if (isnan(expected_value)) {
        EXPECT_TRUE(isnan(top_data[i]));
      } else {
        Dtype precision = max(Dtype(abs(expected_value * 0.0001)),
                              min_precision);
        EXPECT_NEAR(expected_value, top_data[i], precision);
      }
    }
  }

  void TestBackward(Dtype power, Dtype scale, Dtype shift) {
    LayerParameter layer_param;
    layer_param.mutable_power_param()->set_power(power);
    layer_param.mutable_power_param()->set_scale(scale);
    layer_param.mutable_power_param()->set_shift(shift);
    PowerLayer<Dtype> layer(layer_param);
    if (power != Dtype(0) && power != Dtype(1) && power != Dtype(2)) {
      // Avoid NaNs by forcing (shift + scale * x) >= 0
      Dtype* bottom_data = this->blob_bottom_->mutable_cpu_data();
      Dtype min_value = -shift / scale;
      for (int i = 0; i < this->blob_bottom_->count(); ++i) {
        if (bottom_data[i] < min_value) {
          bottom_data[i] = min_value + (min_value - bottom_data[i]);
        }
      }
    }
    GradientChecker<Dtype> checker(1e-2, 1e-2, 1701, 0., 0.01);
    checker.CheckGradientExhaustive(&layer, &(this->blob_bottom_vec_),
        &(this->blob_top_vec_));
  }

  Blob<Dtype>* const blob_bottom_;
  Blob<Dtype>* const blob_top_;
  vector<Blob<Dtype>*> blob_bottom_vec_;
  vector<Blob<Dtype>*> blob_top_vec_;
};

typedef ::testing::Types<float, double> Dtypes;
TYPED_TEST_CASE(PowerLayerTest, Dtypes);

TYPED_TEST(PowerLayerTest, TestPowerCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 0.37;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  TestForward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerGradientCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 0.37;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerGradientShiftZeroCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 0.37;
  TypeParam scale = 0.83;
  TypeParam shift = 0.0;
  TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerZeroCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 0.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  TestForward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerZeroGradientCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 0.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerOneCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 1.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  TestForward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerOneGradientCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 1.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerTwoCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 2.0;
  TypeParam scale = 0.34;
  TypeParam shift = -2.4;
  TestForward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerTwoGradientCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 2.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerTwoScaleHalfGradientCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 2.0;
  TypeParam scale = 0.5;
  TypeParam shift = -2.4;
  TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 0.37;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  TestForward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerGradientGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 0.37;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerGradientShiftZeroGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 0.37;
  TypeParam scale = 0.83;
  TypeParam shift = 0.0;
  TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerZeroGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 0.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  TestForward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerZeroGradientGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 0.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerOneGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 1.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  TestForward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerOneGradientGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 1.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerTwoGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 2.0;
  TypeParam scale = 0.34;
  TypeParam shift = -2.4;
  TestForward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerTwoGradientGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 2.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerTwoScaleHalfGradientGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 2.0;
  TypeParam scale = 0.5;
  TypeParam shift = -2.4;
  TestBackward(power, scale, shift);
}

}  // namespace caffe
<commit_msg>add using std::isnan and use this-> when calling Test{For,Back}ward<commit_after>// Copyright 2014 BVLC and contributors.

#include <algorithm>
#include <vector>

#include "cuda_runtime.h"
#include "gtest/gtest.h"

#include "caffe/blob.hpp"
#include "caffe/common.hpp"
#include "caffe/filler.hpp"
#include "caffe/vision_layers.hpp"
#include "caffe/test/test_gradient_check_util.hpp"

#include "caffe/test/test_caffe_main.hpp"

using std::isnan;

namespace caffe {

extern cudaDeviceProp CAFFE_TEST_CUDA_PROP;

template <typename Dtype>
class PowerLayerTest : public ::testing::Test {
 protected:
  PowerLayerTest()
      : blob_bottom_(new Blob<Dtype>(2, 3, 4, 5)),
        blob_top_(new Blob<Dtype>()) {
    // fill the values
    FillerParameter filler_param;
    GaussianFiller<Dtype> filler(filler_param);
    filler.Fill(this->blob_bottom_);
    blob_bottom_vec_.push_back(blob_bottom_);
    blob_top_vec_.push_back(blob_top_);
  }
  virtual ~PowerLayerTest() { delete blob_bottom_; delete blob_top_; }

  void TestForward(Dtype power, Dtype scale, Dtype shift) {
    LayerParameter layer_param;
    layer_param.mutable_power_param()->set_power(power);
    layer_param.mutable_power_param()->set_scale(scale);
    layer_param.mutable_power_param()->set_shift(shift);
    PowerLayer<Dtype> layer(layer_param);
    layer.SetUp(this->blob_bottom_vec_, &(this->blob_top_vec_));
    layer.Forward(this->blob_bottom_vec_, &(this->blob_top_vec_));
    // Now, check values
    const Dtype* bottom_data = this->blob_bottom_->cpu_data();
    const Dtype* top_data = this->blob_top_->cpu_data();
    const Dtype min_precision = 1e-5;
    for (int i = 0; i < this->blob_bottom_->count(); ++i) {
      Dtype expected_value = pow(shift + scale * bottom_data[i], power);
      if (power == Dtype(0) || power == Dtype(1) || power == Dtype(2)) {
        EXPECT_FALSE(isnan(top_data[i]));
      }
      if (isnan(expected_value)) {
        EXPECT_TRUE(isnan(top_data[i]));
      } else {
        Dtype precision = max(Dtype(abs(expected_value * 0.0001)),
                              min_precision);
        EXPECT_NEAR(expected_value, top_data[i], precision);
      }
    }
  }

  void TestBackward(Dtype power, Dtype scale, Dtype shift) {
    LayerParameter layer_param;
    layer_param.mutable_power_param()->set_power(power);
    layer_param.mutable_power_param()->set_scale(scale);
    layer_param.mutable_power_param()->set_shift(shift);
    PowerLayer<Dtype> layer(layer_param);
    if (power != Dtype(0) && power != Dtype(1) && power != Dtype(2)) {
      // Avoid NaNs by forcing (shift + scale * x) >= 0
      Dtype* bottom_data = this->blob_bottom_->mutable_cpu_data();
      Dtype min_value = -shift / scale;
      for (int i = 0; i < this->blob_bottom_->count(); ++i) {
        if (bottom_data[i] < min_value) {
          bottom_data[i] = min_value + (min_value - bottom_data[i]);
        }
      }
    }
    GradientChecker<Dtype> checker(1e-2, 1e-2, 1701, 0., 0.01);
    checker.CheckGradientExhaustive(&layer, &(this->blob_bottom_vec_),
        &(this->blob_top_vec_));
  }

  Blob<Dtype>* const blob_bottom_;
  Blob<Dtype>* const blob_top_;
  vector<Blob<Dtype>*> blob_bottom_vec_;
  vector<Blob<Dtype>*> blob_top_vec_;
};

typedef ::testing::Types<float, double> Dtypes;
TYPED_TEST_CASE(PowerLayerTest, Dtypes);

TYPED_TEST(PowerLayerTest, TestPowerCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 0.37;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  this->TestForward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerGradientCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 0.37;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  this->TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerGradientShiftZeroCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 0.37;
  TypeParam scale = 0.83;
  TypeParam shift = 0.0;
  this->TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerZeroCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 0.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  this->TestForward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerZeroGradientCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 0.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  this->TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerOneCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 1.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  this->TestForward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerOneGradientCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 1.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  this->TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerTwoCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 2.0;
  TypeParam scale = 0.34;
  TypeParam shift = -2.4;
  this->TestForward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerTwoGradientCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 2.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  this->TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerTwoScaleHalfGradientCPU) {
  Caffe::set_mode(Caffe::CPU);
  TypeParam power = 2.0;
  TypeParam scale = 0.5;
  TypeParam shift = -2.4;
  this->TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 0.37;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  this->TestForward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerGradientGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 0.37;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  this->TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerGradientShiftZeroGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 0.37;
  TypeParam scale = 0.83;
  TypeParam shift = 0.0;
  this->TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerZeroGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 0.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  this->TestForward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerZeroGradientGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 0.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  this->TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerOneGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 1.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  this->TestForward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerOneGradientGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 1.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  this->TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerTwoGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 2.0;
  TypeParam scale = 0.34;
  TypeParam shift = -2.4;
  this->TestForward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerTwoGradientGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 2.0;
  TypeParam scale = 0.83;
  TypeParam shift = -2.4;
  this->TestBackward(power, scale, shift);
}

TYPED_TEST(PowerLayerTest, TestPowerTwoScaleHalfGradientGPU) {
  Caffe::set_mode(Caffe::GPU);
  TypeParam power = 2.0;
  TypeParam scale = 0.5;
  TypeParam shift = -2.4;
  this->TestBackward(power, scale, shift);
}

}  // namespace caffe
<|endoftext|>


<commit_before>/**************************************************************************
 *
 * Copyright 2010 VMware, Inc.
 * Copyright 2011 Intel corporation
 * All Rights Reserved.
 *
 * 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 <sstream>
#include <string.h>
#include <limits.h> // for CHAR_MAX
#include <getopt.h>

#include <set>

#include "cli.hpp"

#include "os_string.hpp"

#include "trace_analyzer.hpp"
#include "trace_callset.hpp"
#include "trace_parser.hpp"
#include "trace_writer.hpp"

static const char *synopsis = "Create a new trace by trimming an existing trace.";

static void
usage(void)
{
    std::cout
        << "usage: apitrace trim [OPTIONS] TRACE_FILE...\n"
        << synopsis << "\n"
        "\n"
        "    -h, --help               Show detailed help for trim options and exit\n"
        "        --calls=CALLSET      Include specified calls in the trimmed output.\n"
        "        --frames=FRAMESET    Include specified frames in the trimmed output.\n"
        "        --deps               Include additional calls to satisfy dependencies\n"
        "        --no-deps            Do not include calls from dependency analysis\n"
        "        --prune              Omit uninteresting calls from the trace output\n"
        "        --no-prune           Do not prune uninteresting calls from the trace.\n"
        "    -x, --exact              Trim exactly to calls specified in --calls/--frames\n"
        "                             Equivalent to both --no-deps and --no-prune\n"
        "        --print-callset      Print the final set of calls included in output\n"
        "        --thread=THREAD_ID   Only retain calls from specified thread\n"
        "    -o, --output=TRACE_FILE  Output trace file\n"
    ;
}

static void
help()
{
    std::cout
        << "usage: apitrace trim [OPTIONS] TRACE_FILE...\n"
        << synopsis << "\n"
        "\n"
        "    -h, --help               Show this help message and exit\n"
        "\n"
        "        --calls=CALLSET      Include specified calls in the trimmed output.\n"
        "        --frames=FRAMESET    Include specified frames in the trimmed output.\n"
        "                             Note that due to dependency analysis and pruning\n"
        "                             of uninteresting calls the resulting trace may\n"
        "                             include more and less calls than specified.\n"
        "                             See --no-deps, --no-prune, and --exact to change\n"
        "                             this behavior.\n"
        "\n"
        "        --deps               Perform dependency analysis and include dependent\n"
        "                             calls as needed, (even if those calls were not\n"
        "                             explicitly requested with --calls or --frames).\n"
        "                             This is the default behavior. See --no-deps and\n"
        "                             --exact to change the behavior.\n"
        "\n"
        "        --no-deps            Do not perform dependency analysis. In this mode\n"
        "                             the trimmed trace will never include calls from\n"
        "                             outside what is specified in --calls or --frames.\n"
        "\n"
        "        --prune              Omit calls with no side effects, even if the call\n"
        "                             is within the range specified by --calls/--frames.\n"
        "                             This is the default behavior. See --no-prune.\n"
        "\n"
        "        --no-prune           Do not prune uninteresting calls from the trace.\n"
        "                             In this mode the trimmed trace will never omit\n"
        "                             any calls within the user-specified range.\n"
        "\n"
        "    -x, --exact              Trim the trace to exactly the calls specified in\n"
        "                             --calls and --frames. This option is equivalent\n"
        "                             to passing both --no-deps and --no-prune.\n"
        "\n"
        "        --print-callset      Print to stdout the final set of calls included\n"
        "                             in the trim output. This can be useful for\n"
        "                             debugging trim operations by using a modified\n"
        "                             callset on the command-line along with --exact.\n"
        "                             Use --calls=@<file> to read callset from a file.\n"
        "\n"
        "        --thread=THREAD_ID   Only retain calls from specified thread\n"
        "\n"
        "    -o, --output=TRACE_FILE  Output trace file\n"
        "\n"
    ;
}

enum {
    CALLS_OPT = CHAR_MAX + 1,
    FRAMES_OPT,
    DEPS_OPT,
    NO_DEPS_OPT,
    PRUNE_OPT,
    NO_PRUNE_OPT,
    THREAD_OPT,
    PRINT_CALLSET_OPT,
};

const static char *
shortOptions = "ho:x";

const static struct option
longOptions[] = {
    {"help", no_argument, 0, 'h'},
    {"calls", required_argument, 0, CALLS_OPT},
    {"frames", required_argument, 0, FRAMES_OPT},
    {"deps", no_argument, 0, DEPS_OPT},
    {"no-deps", no_argument, 0, NO_DEPS_OPT},
    {"prune", no_argument, 0, PRUNE_OPT},
    {"no-prune", no_argument, 0, NO_PRUNE_OPT},
    {"exact", no_argument, 0, 'x'},
    {"thread", required_argument, 0, THREAD_OPT},
    {"output", required_argument, 0, 'o'},
    {"print-callset", no_argument, 0, PRINT_CALLSET_OPT},
    {0, 0, 0, 0}
};

struct stringCompare {
    bool operator() (const char *a, const char *b) const {
        return strcmp(a, b) < 0;
    }
};

struct trim_options {
    /* Calls to be included in trace. */
    trace::CallSet calls;

    /* Frames to be included in trace. */
    trace::CallSet frames;

    /* Whether dependency analysis should be performed. */
    bool dependency_analysis;

    /* Whether uninteresting calls should be pruned.. */
    bool prune_uninteresting;

    /* Output filename */
    std::string output;

    /* Emit only calls from this thread (-1 == all threads) */
    int thread;

    /* Print resulting callset */
    int print_callset;
};

static int
trim_trace(const char *filename, struct trim_options *options)
{
    trace::ParseBookmark beginning;
    trace::Parser p;
    TraceAnalyzer analyzer;
    std::set<unsigned> *required;
    unsigned frame;
    int call_range_first, call_range_last;

    if (!p.open(filename)) {
        std::cerr << "error: failed to open " << filename << "\n";
        return 1;
    }

    /* Mark the beginning so we can return here for pass 2. */
    p.getBookmark(beginning);

    /* In pass 1, analyze which calls are needed. */
    frame = 0;
    trace::Call *call;
    while ((call = p.parse_call())) {

        /* There's no use doing any work past the last call or frame
         * requested by the user. */
        if (call->no > options->calls.getLast() ||
            frame > options->frames.getLast()) {

            delete call;
            break;
        }

        /* If requested, ignore all calls not belonging to the specified thread. */
        if (options->thread != -1 && call->thread_id != options->thread) {
            goto NEXT;
        }

        /* Also, prune if uninteresting (unless the user asked for no pruning. */
        if (options->prune_uninteresting && call->flags & trace::CALL_FLAG_UNINTERESTING) {
            goto NEXT;
        }

        /* If this call is included in the user-specified call set,
         * then require it (and all dependencies) in the trimmed
         * output. */
        if (options->calls.contains(*call) ||
            options->frames.contains(frame, call->flags)) {

            analyzer.require(call);
        }

        /* Regardless of whether we include this call or not, we do
         * some dependency tracking (unless disabled by the user). We
         * do this even for calls we have included in the output so
         * that any state updates get performed. */
        if (options->dependency_analysis) {
            analyzer.analyze(call);
        }

    NEXT:
        if (call->flags & trace::CALL_FLAG_END_FRAME)
            frame++;

        delete call;
    }

    /* Prepare output file and writer for output. */
    if (options->output.empty()) {
        os::String base(filename);
        base.trimExtension();

        options->output = std::string(base.str()) + std::string("-trim.trace");
    }

    trace::Writer writer;
    if (!writer.open(options->output.c_str())) {
        std::cerr << "error: failed to create " << filename << "\n";
        return 1;
    }

    /* Reset bookmark for pass 2. */
    p.setBookmark(beginning);

    /* In pass 2, emit the calls that are required. */
    required = analyzer.get_required();

    frame = 0;
    call_range_first = -1;
    call_range_last = -1;
    while ((call = p.parse_call())) {

        /* There's no use doing any work past the last call or frame
         * requested by the user. */
        if (call->no > options->calls.getLast() ||
            frame > options->frames.getLast()) {

            break;
        }

        if (required->find(call->no) != required->end()) {
            writer.writeCall(call);

            if (options->print_callset) {
                if (call_range_first < 0) {
                    call_range_first = call->no;
                    printf ("%d", call_range_first);
                } else if (call->no != call_range_last + 1) {
                    if (call_range_last != call_range_first)
                        printf ("-%d", call_range_last);
                    call_range_first = call->no;
                    printf (",%d", call_range_first);
                }
                call_range_last = call->no;
            }
        }

        if (call->flags & trace::CALL_FLAG_END_FRAME) {
            frame++;
        }

        delete call;
    }

    if (options->print_callset) {
        if (call_range_last != call_range_first)
            printf ("-%d\n", call_range_last);
    }

    std::cout << "Trimmed trace is available as " << options->output << "\n";

    return 0;
}

static int
command(int argc, char *argv[])
{
    struct trim_options options;

    options.calls = trace::CallSet(trace::FREQUENCY_NONE);
    options.frames = trace::CallSet(trace::FREQUENCY_NONE);
    options.dependency_analysis = true;
    options.prune_uninteresting = true;
    options.output = "";
    options.thread = -1;
    options.print_callset = 0;

    int opt;
    while ((opt = getopt_long(argc, argv, shortOptions, longOptions, NULL)) != -1) {
        switch (opt) {
        case 'h':
            help();
            return 0;
        case CALLS_OPT:
            options.calls = trace::CallSet(optarg);
            break;
        case FRAMES_OPT:
            options.frames = trace::CallSet(optarg);
            break;
        case DEPS_OPT:
            options.dependency_analysis = true;
            break;
        case NO_DEPS_OPT:
            options.dependency_analysis = false;
            break;
        case PRUNE_OPT:
            options.prune_uninteresting = true;
            break;
        case NO_PRUNE_OPT:
            options.prune_uninteresting = false;
            break;
        case 'x':
            options.dependency_analysis = false;
            options.prune_uninteresting = false;
            break;
        case THREAD_OPT:
            options.thread = atoi(optarg);
            break;
        case 'o':
            options.output = optarg;
            break;
        case PRINT_CALLSET_OPT:
            options.print_callset = 1;
            break;
        default:
            std::cerr << "error: unexpected option `" << opt << "`\n";
            usage();
            return 1;
        }
    }

    /* If neither of --calls nor --frames was set, default to the
     * entire set of calls. */
    if (options.calls.empty() && options.frames.empty()) {
        options.calls = trace::CallSet(trace::FREQUENCY_ALL);
    }

    if (optind >= argc) {
        std::cerr << "error: apitrace trim requires a trace file as an argument.\n";
        usage();
        return 1;
    }

    if (argc > optind + 1) {
        std::cerr << "error: extraneous arguments:";
        for (int i = optind + 1; i < argc; i++) {
            std::cerr << " " << argv[i];
        }
        std::cerr << "\n";
        usage();
        return 1;
    }

    return trim_trace(argv[optind], &options);
}

const Command trim_command = {
    "trim",
    synopsis,
    help,
    command
};
<commit_msg>trim: Print a warning message when doing dependency analysis.<commit_after>/**************************************************************************
 *
 * Copyright 2010 VMware, Inc.
 * Copyright 2011 Intel corporation
 * All Rights Reserved.
 *
 * 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 <sstream>
#include <string.h>
#include <limits.h> // for CHAR_MAX
#include <getopt.h>

#include <set>

#include "cli.hpp"

#include "os_string.hpp"

#include "trace_analyzer.hpp"
#include "trace_callset.hpp"
#include "trace_parser.hpp"
#include "trace_writer.hpp"

static const char *synopsis = "Create a new trace by trimming an existing trace.";

static void
usage(void)
{
    std::cout
        << "usage: apitrace trim [OPTIONS] TRACE_FILE...\n"
        << synopsis << "\n"
        "\n"
        "    -h, --help               Show detailed help for trim options and exit\n"
        "        --calls=CALLSET      Include specified calls in the trimmed output.\n"
        "        --frames=FRAMESET    Include specified frames in the trimmed output.\n"
        "        --deps               Include additional calls to satisfy dependencies\n"
        "        --no-deps            Do not include calls from dependency analysis\n"
        "        --prune              Omit uninteresting calls from the trace output\n"
        "        --no-prune           Do not prune uninteresting calls from the trace.\n"
        "    -x, --exact              Trim exactly to calls specified in --calls/--frames\n"
        "                             Equivalent to both --no-deps and --no-prune\n"
        "        --print-callset      Print the final set of calls included in output\n"
        "        --thread=THREAD_ID   Only retain calls from specified thread\n"
        "    -o, --output=TRACE_FILE  Output trace file\n"
    ;
}

static void
help()
{
    std::cout
        << "usage: apitrace trim [OPTIONS] TRACE_FILE...\n"
        << synopsis << "\n"
        "\n"
        "    -h, --help               Show this help message and exit\n"
        "\n"
        "        --calls=CALLSET      Include specified calls in the trimmed output.\n"
        "        --frames=FRAMESET    Include specified frames in the trimmed output.\n"
        "                             Note that due to dependency analysis and pruning\n"
        "                             of uninteresting calls the resulting trace may\n"
        "                             include more and less calls than specified.\n"
        "                             See --no-deps, --no-prune, and --exact to change\n"
        "                             this behavior.\n"
        "\n"
        "        --deps               Perform dependency analysis and include dependent\n"
        "                             calls as needed, (even if those calls were not\n"
        "                             explicitly requested with --calls or --frames).\n"
        "                             This is the default behavior. See --no-deps and\n"
        "                             --exact to change the behavior.\n"
        "\n"
        "        --no-deps            Do not perform dependency analysis. In this mode\n"
        "                             the trimmed trace will never include calls from\n"
        "                             outside what is specified in --calls or --frames.\n"
        "\n"
        "        --prune              Omit calls with no side effects, even if the call\n"
        "                             is within the range specified by --calls/--frames.\n"
        "                             This is the default behavior. See --no-prune.\n"
        "\n"
        "        --no-prune           Do not prune uninteresting calls from the trace.\n"
        "                             In this mode the trimmed trace will never omit\n"
        "                             any calls within the user-specified range.\n"
        "\n"
        "    -x, --exact              Trim the trace to exactly the calls specified in\n"
        "                             --calls and --frames. This option is equivalent\n"
        "                             to passing both --no-deps and --no-prune.\n"
        "\n"
        "        --print-callset      Print to stdout the final set of calls included\n"
        "                             in the trim output. This can be useful for\n"
        "                             debugging trim operations by using a modified\n"
        "                             callset on the command-line along with --exact.\n"
        "                             Use --calls=@<file> to read callset from a file.\n"
        "\n"
        "        --thread=THREAD_ID   Only retain calls from specified thread\n"
        "\n"
        "    -o, --output=TRACE_FILE  Output trace file\n"
        "\n"
    ;
}

enum {
    CALLS_OPT = CHAR_MAX + 1,
    FRAMES_OPT,
    DEPS_OPT,
    NO_DEPS_OPT,
    PRUNE_OPT,
    NO_PRUNE_OPT,
    THREAD_OPT,
    PRINT_CALLSET_OPT,
};

const static char *
shortOptions = "ho:x";

const static struct option
longOptions[] = {
    {"help", no_argument, 0, 'h'},
    {"calls", required_argument, 0, CALLS_OPT},
    {"frames", required_argument, 0, FRAMES_OPT},
    {"deps", no_argument, 0, DEPS_OPT},
    {"no-deps", no_argument, 0, NO_DEPS_OPT},
    {"prune", no_argument, 0, PRUNE_OPT},
    {"no-prune", no_argument, 0, NO_PRUNE_OPT},
    {"exact", no_argument, 0, 'x'},
    {"thread", required_argument, 0, THREAD_OPT},
    {"output", required_argument, 0, 'o'},
    {"print-callset", no_argument, 0, PRINT_CALLSET_OPT},
    {0, 0, 0, 0}
};

struct stringCompare {
    bool operator() (const char *a, const char *b) const {
        return strcmp(a, b) < 0;
    }
};

struct trim_options {
    /* Calls to be included in trace. */
    trace::CallSet calls;

    /* Frames to be included in trace. */
    trace::CallSet frames;

    /* Whether dependency analysis should be performed. */
    bool dependency_analysis;

    /* Whether uninteresting calls should be pruned.. */
    bool prune_uninteresting;

    /* Output filename */
    std::string output;

    /* Emit only calls from this thread (-1 == all threads) */
    int thread;

    /* Print resulting callset */
    int print_callset;
};

static int
trim_trace(const char *filename, struct trim_options *options)
{
    trace::ParseBookmark beginning;
    trace::Parser p;
    TraceAnalyzer analyzer;
    std::set<unsigned> *required;
    unsigned frame;
    int call_range_first, call_range_last;

    if (!p.open(filename)) {
        std::cerr << "error: failed to open " << filename << "\n";
        return 1;
    }

    /* Mark the beginning so we can return here for pass 2. */
    p.getBookmark(beginning);

    /* In pass 1, analyze which calls are needed. */
    frame = 0;
    trace::Call *call;
    while ((call = p.parse_call())) {

        /* There's no use doing any work past the last call or frame
         * requested by the user. */
        if (call->no > options->calls.getLast() ||
            frame > options->frames.getLast()) {

            delete call;
            break;
        }

        /* If requested, ignore all calls not belonging to the specified thread. */
        if (options->thread != -1 && call->thread_id != options->thread) {
            goto NEXT;
        }

        /* Also, prune if uninteresting (unless the user asked for no pruning. */
        if (options->prune_uninteresting && call->flags & trace::CALL_FLAG_UNINTERESTING) {
            goto NEXT;
        }

        /* If this call is included in the user-specified call set,
         * then require it (and all dependencies) in the trimmed
         * output. */
        if (options->calls.contains(*call) ||
            options->frames.contains(frame, call->flags)) {

            analyzer.require(call);
        }

        /* Regardless of whether we include this call or not, we do
         * some dependency tracking (unless disabled by the user). We
         * do this even for calls we have included in the output so
         * that any state updates get performed. */
        if (options->dependency_analysis) {
            analyzer.analyze(call);
        }

    NEXT:
        if (call->flags & trace::CALL_FLAG_END_FRAME)
            frame++;

        delete call;
    }

    /* Prepare output file and writer for output. */
    if (options->output.empty()) {
        os::String base(filename);
        base.trimExtension();

        options->output = std::string(base.str()) + std::string("-trim.trace");
    }

    trace::Writer writer;
    if (!writer.open(options->output.c_str())) {
        std::cerr << "error: failed to create " << filename << "\n";
        return 1;
    }

    /* Reset bookmark for pass 2. */
    p.setBookmark(beginning);

    /* In pass 2, emit the calls that are required. */
    required = analyzer.get_required();

    frame = 0;
    call_range_first = -1;
    call_range_last = -1;
    while ((call = p.parse_call())) {

        /* There's no use doing any work past the last call or frame
         * requested by the user. */
        if (call->no > options->calls.getLast() ||
            frame > options->frames.getLast()) {

            break;
        }

        if (required->find(call->no) != required->end()) {
            writer.writeCall(call);

            if (options->print_callset) {
                if (call_range_first < 0) {
                    call_range_first = call->no;
                    printf ("%d", call_range_first);
                } else if (call->no != call_range_last + 1) {
                    if (call_range_last != call_range_first)
                        printf ("-%d", call_range_last);
                    call_range_first = call->no;
                    printf (",%d", call_range_first);
                }
                call_range_last = call->no;
            }
        }

        if (call->flags & trace::CALL_FLAG_END_FRAME) {
            frame++;
        }

        delete call;
    }

    if (options->print_callset) {
        if (call_range_last != call_range_first)
            printf ("-%d\n", call_range_last);
    }

    std::cout << "Trimmed trace is available as " << options->output << "\n";

    return 0;
}

static int
command(int argc, char *argv[])
{
    struct trim_options options;

    options.calls = trace::CallSet(trace::FREQUENCY_NONE);
    options.frames = trace::CallSet(trace::FREQUENCY_NONE);
    options.dependency_analysis = true;
    options.prune_uninteresting = true;
    options.output = "";
    options.thread = -1;
    options.print_callset = 0;

    int opt;
    while ((opt = getopt_long(argc, argv, shortOptions, longOptions, NULL)) != -1) {
        switch (opt) {
        case 'h':
            help();
            return 0;
        case CALLS_OPT:
            options.calls = trace::CallSet(optarg);
            break;
        case FRAMES_OPT:
            options.frames = trace::CallSet(optarg);
            break;
        case DEPS_OPT:
            options.dependency_analysis = true;
            break;
        case NO_DEPS_OPT:
            options.dependency_analysis = false;
            break;
        case PRUNE_OPT:
            options.prune_uninteresting = true;
            break;
        case NO_PRUNE_OPT:
            options.prune_uninteresting = false;
            break;
        case 'x':
            options.dependency_analysis = false;
            options.prune_uninteresting = false;
            break;
        case THREAD_OPT:
            options.thread = atoi(optarg);
            break;
        case 'o':
            options.output = optarg;
            break;
        case PRINT_CALLSET_OPT:
            options.print_callset = 1;
            break;
        default:
            std::cerr << "error: unexpected option `" << opt << "`\n";
            usage();
            return 1;
        }
    }

    /* If neither of --calls nor --frames was set, default to the
     * entire set of calls. */
    if (options.calls.empty() && options.frames.empty()) {
        options.calls = trace::CallSet(trace::FREQUENCY_ALL);
    }

    if (optind >= argc) {
        std::cerr << "error: apitrace trim requires a trace file as an argument.\n";
        usage();
        return 1;
    }

    if (argc > optind + 1) {
        std::cerr << "error: extraneous arguments:";
        for (int i = optind + 1; i < argc; i++) {
            std::cerr << " " << argv[i];
        }
        std::cerr << "\n";
        usage();
        return 1;
    }

    if (options.dependency_analysis) {
        std::cerr <<
            "Note: The dependency analysis in \"apitrace trim\" is still experimental.\n"
            "      We hope that it will be useful, but it may lead to incorrect results.\n"
            "      If you find a trace that misbehaves while trimming, please share that\n"
            "      by sending email to apitrace@lists.freedesktop.org, cworth@cworth.org\n";
    }

    return trim_trace(argv[optind], &options);
}

const Command trim_command = {
    "trim",
    synopsis,
    help,
    command
};
<|endoftext|>


<commit_before>// Copyright (c) 2019, 2021 by Robert Bosch GmbH, Apex.AI Inc. All rights reserved.
//
// 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 "iceoryx_posh/roudi/iceoryx_roudi_app.hpp"
#include "iceoryx_posh/roudi/roudi_cmd_line_parser_config_file_option.hpp"
#include "iceoryx_posh/roudi/roudi_config_toml_file_provider.hpp"
#include "iceoryx_posh/internal/log/posh_logging.hpp"

#include <gmock/gmock.h>
#include <gtest/gtest.h>

using namespace ::testing;
using ::testing::Return;

using iox::roudi::IceOryxRouDiApp;

namespace iox
{
namespace test
{

class IceoryxRoudiApp_Child : public IceOryxRouDiApp
{
    public:

    IceoryxRoudiApp_Child(const config::CmdLineParser& cmdLineParser, const RouDiConfig_t& roudiConfig):IceOryxRouDiApp(cmdLineParser,roudiConfig)
    {
    }

    bool getVariableMRun()
    {
        return m_run;
    }

    void setVariableMRun(bool condition)
    {
        m_run = condition;
    }

    uint8_t callRun() noexcept
    {
        return run();
    }
};

/// @brief Test goal: This file tests class roudi app
class IceoryxRoudiApp_test : public Test
{
  public:

    iox::config::CmdLineParserConfigFileOption cmdLineParser;
    int argc;
    char* argv[];

    virtual void setUp()
    {
        cmdLineParser.parse(argc, argv);
    }
};

TEST_F(IceoryxRoudiApp_test, CheckConstructorIsSuccessfull)
{
    IceoryxRoudiApp_Child roudi(cmdLineParser, iox::RouDiConfig_t().setDefaults());

    EXPECT_TRUE(roudi.getVariableMRun());
}

TEST_F(IceoryxRoudiApp_test, CheckRunMethodWithMRunFalseReturnExitSuccess)
{
    IceoryxRoudiApp_Child roudi(cmdLineParser, iox::RouDiConfig_t().setDefaults());

    roudi.setVariableMRun(false);

    uint8_t result = roudi.callRun();

    EXPECT_EQ(result, EXIT_SUCCESS);
}

} // namespace test
} // namespace iox<commit_msg>iox-#454 improve test for roudi app<commit_after>// Copyright (c) 2019, 2021 by Robert Bosch GmbH, Apex.AI Inc. All rights reserved.
//
// 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 "iceoryx_posh/roudi/iceoryx_roudi_app.hpp"
#include "iceoryx_posh/roudi/roudi_cmd_line_parser_config_file_option.hpp"
#include "iceoryx_posh/roudi/roudi_config_toml_file_provider.hpp"
#include "iceoryx_posh/internal/log/posh_logging.hpp"

#include <gmock/gmock.h>
#include <gtest/gtest.h>

using namespace ::testing;
using ::testing::Return;

using iox::roudi::IceOryxRouDiApp;

namespace iox
{
namespace test
{

class IceoryxRoudiApp_Child : public IceOryxRouDiApp
{
    public:

    IceoryxRoudiApp_Child(const config::CmdLineArgs_t& cmdLineArgs, const RouDiConfig_t& roudiConfig):IceOryxRouDiApp(cmdLineArgs,roudiConfig)
    {
    }

    bool getVariableMRun()
    {
        return m_run;
    }

    void setVariableMRun(bool condition)
    {
        m_run = condition;
    }

    uint8_t callRun() noexcept
    {
        return run();
    }
};

/// @brief Test goal: This file tests class roudi app
class IceoryxRoudiApp_test : public Test
{
  public:

    iox::config::CmdLineParserConfigFileOption cmdLineParser;

    virtual void setUp()
    {

    }
};

TEST_F(IceoryxRoudiApp_test, CheckConstructorIsSuccessfull)
{
    constexpr uint8_t numberOfArgs{1U};
    char* args[numberOfArgs];
    char appName[] = "./foo";
    args[0] = &appName[0];

    auto cmdLineArgs = cmdLineParser.parse(numberOfArgs, args);

    IceoryxRoudiApp_Child roudi(cmdLineArgs.value(), iox::RouDiConfig_t().setDefaults());

    EXPECT_TRUE(roudi.getVariableMRun());
}

TEST_F(IceoryxRoudiApp_test, CreateTwoRoudiAppIsSuccessfull)
{
    constexpr uint8_t numberOfArgs{1U};
    char* args[numberOfArgs];
    char appName[] = "./foo";
    args[0] = &appName[0];

    auto cmdLineArgs = cmdLineParser.parse(numberOfArgs, args);

    IceoryxRoudiApp_Child roudi(cmdLineArgs.value(), iox::RouDiConfig_t().setDefaults());

    IceoryxRoudiApp_Child roudiTest(cmdLineArgs.value(), iox::RouDiConfig_t().setDefaults());

    EXPECT_TRUE(roudiTest.getVariableMRun());
}

TEST_F(IceoryxRoudiApp_test, CheckRunMethodWithMRunFalseReturnExitSuccess)
{
    constexpr uint8_t numberOfArgs{1U};
    char* args[numberOfArgs];
    char appName[] = "./foo";
    args[0] = &appName[0];

    auto cmdLineArgs = cmdLineParser.parse(numberOfArgs, args);

    IceoryxRoudiApp_Child roudi(cmdLineArgs.value(), iox::RouDiConfig_t().setDefaults());

    roudi.setVariableMRun(false);

    uint8_t result = roudi.callRun();

    EXPECT_EQ(result, EXIT_SUCCESS);
}

TEST_F(IceoryxRoudiApp_test, ConstructorCalledWithArgVersionSetRunVariableToFalse)
{
    constexpr uint8_t numberOfArgs{2U};
    char* args[numberOfArgs];
    char appName[] = "./foo";
    char option[] = "-v";
    args[0] = &appName[0];
    args[1] = &option[0];

    auto cmdLineArgs = cmdLineParser.parse(numberOfArgs, args);

    IceoryxRoudiApp_Child roudi(cmdLineArgs.value(), iox::RouDiConfig_t().setDefaults());

    EXPECT_FALSE(roudi.getVariableMRun());
}

/*TEST_F(IceoryxRoudiApp_test, ConstructorCalledWithArgUniqueIdSetRunVariableToFalse)
{
    constexpr uint8_t numberOfArgs{3U};
    char* args[numberOfArgs];
    char appName[] = "./foo";
    char option[] = "-u";
    char value[] = "4242";
    args[0] = &appName[0];
    args[1] = &option[0];
    args[2] = &value[0];

    auto cmdLineArgs = cmdLineParser.parse(numberOfArgs, args);

    iox::cxx::optional<iox::Error> detectedError;
    auto errorHandlerGuard = iox::ErrorHandler::SetTemporaryErrorHandler(
        [&detectedError](const iox::Error error, const std::function<void()>, const iox::ErrorLevel errorLevel) {
            detectedError.emplace(error);
            EXPECT_THAT(errorLevel, Eq(iox::ErrorLevel::MODERATE));
        });

    IceoryxRoudiApp_Child roudi(cmdLineArgs.value(), iox::RouDiConfig_t().setDefaults());

    IceoryxRoudiApp_Child roudiTest(cmdLineArgs.value(), iox::RouDiConfig_t().setDefaults());

    ASSERT_THAT(detectedError.has_value(), Eq(true));
    EXPECT_THAT(detectedError.value(),
                Eq(iox::Error::kPOPO__TYPED_UNIQUE_ID_ROUDI_HAS_ALREADY_DEFINED_UNIQUE_ID));
}*/

} // namespace test
} // namespace iox<|endoftext|>


<commit_before>/*!
@file

@copyright Edouard Alligand and Joel Falcou 2015-2017
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
#ifndef BOOST_BRIGAND_FUNCTIONS_BITWISE_SHIFT_LEFT_HPP
#define BOOST_BRIGAND_FUNCTIONS_BITWISE_SHIFT_LEFT_HPP

#include <brigand/types/integral_constant.hpp>

namespace brigand
{
  template <typename A, typename B>
  struct shift_left : brigand::integral_constant<typename A::value_type, (A::value << B::value)> {};
}
#endif
<commit_msg>Delete shift_left.hpp<commit_after><|endoftext|>


<commit_before>///
///@Author  PEZY
///@Date    Aug. 2014
///@Brief
/// read a sequence of strings from cin and
/// store those values in a vector.
///

#include <iostream>
#include <vector>
#include <string>

int main()
{
  std::vector<std::string> vec;
  std::string str;
  while (std::cin >> str)
    vec.push_back(str);

  return 0;
}
<commit_msg>Update ex3_15.cpp<commit_after>///
///@Author  @PEZY @Yue Wang
///@Date    Aug. 2014, Jun 2015
///@Brief
/// read a sequence of strings from cin and
/// store those values in a vector.
///

#include <iostream>
#include <vector>
#include <string>

int main()
{
    std::vector<std::string> vec;
    for (std::string buffer; std::cin >> buffer; vec.push_back(buffer));

    return 0;
}
<|endoftext|>


<commit_before>//
//  ex7_07.cpp
//  Exercise 7.7
//
//  Created by pezy on 11/8/14.
//  Copyright (c) 2014 pezy. All rights reserved.
//

#include "ex7_06.h"

int main()
{
    Sales_data total;
    if (read(std::cin, total)) {
        Sales_data trans;
        while (read(std::cin, trans)) {
            if (total.isbn() == trans.isbn())
                total.combine(trans);
            else {
                print(std::cout, total) << std::endl;
                total = trans;
            }
        }
        print(std::cout, total) << std::endl;
    }
    else {
        std::cerr << "No data?!" << std::endl;
        return -1;
    }

    return 0;
}
<commit_msg>Update ex7_07.cpp<commit_after>//
//  ex7_07.cpp
//  Exercise 7.7
//
//  Created by pezy on 11/8/14.
//  Copyright (c) 2014 pezy. All rights reserved.
//

#include "ex7_06.h"
#include <iostream>
using std::cin;
using std::cout;
using std::cerr;
using std::endl;

int main()
{
    Sales_data total;
    if (read(cin, total)) {
        Sales_data trans;
        while (read(cin, trans)) {
            if (total.isbn() == trans.isbn())
                total.combine(trans);
            else {
                print(cout, total) << endl;
                total = trans;
            }
        }
        print(cout, total) << endl;
    }
    else {
        cerr << "No data?!" << std::endl;
        return -1;
    }

    return 0;
}
<|endoftext|>


<commit_before>//! @file   Exercise 9.27
//! @author pezy
//! @date   2014-12-03
//! @Brief  Write a program to find and remove the odd-valued elements in a forward_list<int>.

#include<iostream>
#include <forward_list>
using namespace std;
int main()
{

	forward_list<int> flst{0,1,2,3,4,5,6,7,8,9};

	for(auto prev=flst.before_begin(), curr=flst.begin(); curr!=flst.end(); )
        if(*curr & 0x1)
            curr=flst.erase_after(prev);
        else
        {
            prev=curr;
            ++curr;
        }
            for(auto i: flst)
        cout<<i<<" ";
    cout<<endl;
}
<commit_msg>Update ex9_27.cpp<commit_after>//! @file   Exercise 9.27
//! @author pezy
//! @date   2014-12-03
//! @Brief  Write a program to find and remove the odd-valued elements in a forward_list<int>.

#include<iostream>
#include <forward_list>
using namespace std;

int main()
{

	forward_list<int> flst{0,1,2,3,4,5,6,7,8,9};

	for(auto prev=flst.before_begin(), curr=flst.begin(); curr!=flst.end(); )
        if(*curr & 0x1)
            curr=flst.erase_after(prev);
        else
        {
            prev=curr;
            ++curr;
        }
            for(auto i: flst)
        cout<<i<<" ";
    cout<<endl;
}
<|endoftext|>


<commit_before>/*
Ex 6.7: Write a grammar for bitwise logical expressions. A bitwise logical
expression is much like an arithmetic expression except that the operators are !
(not), ~ (complement), & (and), | (or), and ^ (exclusive or). Each operator does
its operation to each bit of its integer operands (see §25.5). ! and ~ are
prefix unary operators. A ^ binds tighter than a | (just as * binds tighter than
+) so that x|y^z means x|(y^z) rather than (x|y)^z. The & operator binds tighter
than ^ so that x^y&z means x^(y&z).*/
/*

// | < ^ < & < ~!

Grammar:
    Expression:
        Term
        Expression | Term // Handle |
    Term:
        Primary
        Term ^ Primary
    Primary
        Unit
        Primary & Unit
    Unit
        Number(int form)
        ~Number
        !Number
        ( Expression )
        ~( Expression )
        !( Expression )

*/

#include "std_lib_facilities.h"
#include <cassert>

//------------------------------------------------------------------------------

class Token{
public:
    char kind;
    int value;
    Token(char ch)
        : kind(ch), value(0) {}
    Token(char ch, int val)
        : kind(ch), value(val) {}
};

//------------------------------------------------------------------------------

class Token_stream{
public:
    Token_stream();
    Token get();
    void putback(Token t);
private:
    bool full;
    Token buffer;
};

Token_stream::Token_stream()
    : full(false), buffer(0)
{}

Token Token_stream::get(){
    if(full){
        full = false;
        return buffer;
    }

    char ch;
    cin >> ch;
    switch(ch){
        case ';':
        case 'q':
        case '~': case '!': case '^': case '|': case '%': case '(' : case ')':
                return Token(ch);
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '9':
                return Token('8', ch - '0');
        default:
            error("Bad Token");
    }
}

//------------------------------------------------------------------------------

// The putback() member function puts its argument back into the Token_stream's buffer:
void Token_stream::putback(Token t)
{
    if (full) error("putback() into a full buffer");
    buffer = t;       // copy t to buffer
    full = true;      // buffer is now full
}

int Unit();
int Primary();
int Term();
int Expression();

Token_stream ts;

int Expression(){
    int left = Term();
    Token t = ts.get();
    while(true){
        if(t.kind == '|'){
            left |= Expression();
            t = ts.get();
        }else{
            ts.putback(t);
            return left;
        }
    }
}

int Term(){
    int left = Primary();
    Token t = ts.get();
    while(true){
        if(t.kind == '^'){
            left ^= Expression();
            t = ts.get();
        }else{
            ts.putback(t);
            return left;
        }
    }
}

int Primary(){
    int left = Unit();
    Token t = ts.get();
    while(true){
        if(t.kind == '&'){
            left &= Expression();
            t = ts.get();
        }else{
            ts.putback(t);
            return left;
        }
    }
}

int Unit(){
    Token t = ts.get();
    switch(t.kind){
        case '8':
            return t.value;
        case '(':
        {
            int ret = Expression();
                ret = !ret;
                t = ts.get();
                if(t.kind != ')')
                    error("Nead )");
            return ret;
        }
        case '~':
        {
            t = ts.get();
            if(t.kind == '8')
                return ~(t.value);
            if(t.kind == '('){
                int ret = Expression();
                ret = ~ret;
                t = ts.get();
                if(t.kind != ')')
                    error("Nead )");
                return ret;
            }

        }
        case '!':
        {
            t = ts.get();
            if(t.kind == '8')
                return !(t.value);
            if(t.kind == '('){
                int ret = Expression();
                ret = !ret;
                t = ts.get();
                if(t.kind != ')')
                    error("Nead )");
                return ret;
            }

        }
    }
}

int main(){
    try{
        int val = 0;
        cout << "Please input the logical expression, end with ; " << endl;
        while(cin){
            Token t = ts.get();

            if(t.kind == 'q') break;
            if(t.kind == ';')
                cout << " = " << val << endl;
            else
                ts.putback(t);
            val = Expression();
        }
    }
    catch (exception& e) {
        cerr << "error: " << e.what() << '\n';
        keep_window_open();
        return 1;
    }
    catch (...) {
        cerr << "Oops: unknown exception!\n";
        keep_window_open();
        return 2;
    }
}
<commit_msg>Fix Ex6.7<commit_after>/*
Ex 6.7: Write a grammar for bitwise logical expressions. A bitwise logical
expression is much like an arithmetic expression except that the operators are !
(not), ~ (complement), & (and), | (or), and ^ (exclusive or). Each operator does
its operation to each bit of its integer operands (see §25.5). ! and ~ are
prefix unary operators. A ^ binds tighter than a | (just as * binds tighter than
+) so that x|y^z means x|(y^z) rather than (x|y)^z. The & operator binds tighter
than ^ so that x^y&z means x^(y&z).*/
/*

// | < ^ < & < ~!

Grammar:
    Expression:
        Term
        Expression | Term // Handle |
    Term:
        Primary
        Term ^ Primary
    Primary
        Unit
        Primary & Unit
    Unit
        Number(int form)
        ~Number
        !Number
        ( Expression )
        ~( Expression )
        !( Expression )

*/

#include "std_lib_facilities.h"
#include <cassert>

//------------------------------------------------------------------------------

class Token{
public:
    char kind;
    int value;
    Token(char ch)
        : kind(ch), value(0) {}
    Token(char ch, int val)
        : kind(ch), value(val) {}
};

//------------------------------------------------------------------------------

class Token_stream{
public:
    Token_stream();
    Token get();
    void putback(Token t);
private:
    bool full;
    Token buffer;
};

Token_stream::Token_stream()
    : full(false), buffer(0)
{}

Token Token_stream::get(){
    if(full){
        full = false;
        return buffer;
    }

    char ch;
    cin >> ch;
    switch(ch){
        case ';':
        case 'q':
        case '~': case '!': case '^': case '|': case '&': case '(' : case ')':
                return Token(ch);
        case '0': case '1': case '2': case '3': case '4':
        case '5': case '6': case '7': case '9':
                return Token('8', ch - '0');
        default:
            error("Bad Token");
    }
}

//------------------------------------------------------------------------------

// The putback() member function puts its argument back into the Token_stream's buffer:
void Token_stream::putback(Token t)
{
    if (full) error("putback() into a full buffer");
    buffer = t;       // copy t to buffer
    full = true;      // buffer is now full
}

int Unit();
int Primary();
int Term();
int Expression();

Token_stream ts;

int Expression(){
    int left = Term();
    Token t = ts.get();
    while(true){
        if(t.kind == '|'){
            left |= Expression();
            t = ts.get();
        }else{
            ts.putback(t);
            return left;
        }
    }
}

int Term(){
    int left = Primary();
    Token t = ts.get();
    while(true){
        if(t.kind == '^'){
            left ^= Expression();
            t = ts.get();
        }else{
            ts.putback(t);
            return left;
        }
    }
}

int Primary(){
    int left = Unit();
    Token t = ts.get();
    while(true){
        if(t.kind == '&'){
            left &= Expression();
            t = ts.get();
        }else{
            ts.putback(t);
            return left;
        }
    }
}

int Unit(){
    Token t = ts.get();
    switch(t.kind){
        case '8':
            return t.value;
        case '(':
        {
            int ret = Expression();
                ret = !ret;
                t = ts.get();
                if(t.kind != ')')
                    error("Nead )");
            return ret;
        }
        case '~':
        {
            t = ts.get();
            if(t.kind == '8')
                return ~(t.value);
            if(t.kind == '('){
                int ret = Expression();
                ret = ~ret;
                t = ts.get();
                if(t.kind != ')')
                    error("Nead )");
                return ret;
            }

        }
        case '!':
        {
            t = ts.get();
            if(t.kind == '8')
                return !(t.value);
            if(t.kind == '('){
                int ret = Expression();
                ret = !ret;
                t = ts.get();
                if(t.kind != ')')
                    error("Nead )");
                return ret;
            }

        }
    }
}

int main(){
    try{
        int val = 0;
        cout << "Please input the logical expression, end with ; " << endl;
        while(cin){
            Token t = ts.get();

            if(t.kind == 'q') break;
            if(t.kind == ';')
                cout << " = " << val << endl;
            else
                ts.putback(t);
            val = Expression();
        }
    }
    catch (exception& e) {
        cerr << "error: " << e.what() << '\n';
        keep_window_open();
        return 1;
    }
    catch (...) {
        cerr << "Oops: unknown exception!\n";
        keep_window_open();
        return 2;
    }
}
<|endoftext|>


<commit_before>#include "types.h"
#include "amd64.h"
#include "kernel.hh"
#include "cpu.hh"
#include "gc.hh"
#include "percpu.hh"
#include "spinlock.h"
#include "condvar.h"
#include "proc.hh"
#include "uwq.hh"
#include "vm.hh"
#include "kalloc.hh"
#include "bits.hh"
extern "C" {
#include "kern_c.h"
}

bool
uwq_trywork(void)
{
  // Returning true means uwq added a thread to the run queue

  u64 i, k;

  // A "random" victim CPU
  k = rdtsc();
  for (i = 0; i < NCPU; i++) {
    u64 j = (i+k) % NCPU;

    if (j == mycpuid())
      continue;
    struct cpu *c = &cpus[j];

    // The gc_epoch is for p and uwq
    scoped_gc_epoch xgc();
    barrier();

    struct proc *p = c->proc;
    if (p == nullptr)
      continue;
    uwq* uwq = p->uwq;
    if (uwq == nullptr)
      continue;

    if (uwq->haswork()) {
      if (uwq->tryworker())
        return true;
      break;
    }
  }

  return false;
}

long
sys_wqwait(void)
{
  uwq_worker* w = myproc()->worker;
  if (w == nullptr)
    return -1;

  return w->wait();
}

//
// uwq_worker
//
uwq_worker::uwq_worker(uwq* u, proc* p)
  : uwq_(u), proc_(p), running_(false)
{
  initlock(&lock_, "worker_lock", 0);
  initcondvar(&cv_, "worker_cv");
}

void
uwq_worker::exit(void)
{
  if (--uwq_->uref_ == 0)
    gc_delayed(uwq_);
  release(&lock_);
  delete this;
  ::exit();
}

long
uwq_worker::wait(void)
{
  acquire(&lock_);
  if (!uwq_->valid())
    this->exit();

  running_ = false;
  cv_sleep(&cv_, &lock_);

  if (!uwq_->valid())
    this->exit();
  release(&lock_);
  return 0;
}

//
// uwq
//
uwq*
uwq::alloc(vmap* vmap, filetable *ftable)
{
  uwq_ipcbuf* ipc;
  uwq* u;

  ipc = (uwq_ipcbuf*) ksalloc(slab_userwq);
  if (ipc == nullptr)
    return nullptr;

  ftable->incref();
  vmap->incref();

  u = new uwq(vmap, ftable, ipc);
  if (u == nullptr) {
    ftable->decref();
    vmap->decref();
    ksfree(slab_userwq, ipc);
    return nullptr;
  }

  if (mapkva(vmap->pml4, (char*)ipc, USERWQ, USERWQSIZE)) {
    ftable->decref();
    vmap->decref();
    ksfree(slab_userwq, ipc);
    u->dec();
    return nullptr;
  }

  return u;
}

uwq::uwq(vmap* vmap, filetable* ftable, uwq_ipcbuf* ipc)
  : rcu_freed("uwq"),
    vmap_(vmap), ftable_(ftable), ipc_(ipc),
    uentry_(0), ustack_(UWQSTACK), uref_(0)
{
  for (int i = 0; i < NCPU; i++)
    ipc_->len[i].v_ = 0;

  initlock(&lock_, "uwq_lock", 0);

  for (int i = 0; i < NWORKERS; i++)
    worker_[i].store(nullptr);
}

uwq::~uwq(void)
{
  if (ipc_ != nullptr)
    ksfree(slab_userwq, ipc_);
  vmap_->decref();
  ftable_->decref();
}

bool
uwq::haswork(void) const
{
  if (ipc_ == nullptr)
    return false;

  for (int i = 0; i < NCPU; i++) {
    if (ipc_->len[i].v_ > 0) {
      return true;
    }
  }
  return false;
}

bool
uwq::tryworker(void)
{
  if (!valid())
    return false;

  // Try to start a worker thread
  scoped_acquire lock0(&lock_);

  for (int i = 0; i < NWORKERS; i++) {
    if (worker_[i] == nullptr)
      continue;

    uwq_worker *w = worker_[i];
    if (w->running_)
      continue;
    else {
      scoped_acquire lock1(&w->lock_);
      proc* p = w->proc_;

      acquire(&p->lock);
      p->cpuid = mycpuid();
      release(&p->lock);

      w->running_ = true;
      cv_wakeup(&w->cv_);
      return true;
    }
  }
  lock0.release();

again:
  u64 uref = uref_.load();
  if (uref < ipc_->maxworkers) {
    if (!cmpxch(&uref_, uref, uref+1))
      goto again;
    // Guaranteed to have  slot in worker_

    proc* p = allocworker();
    if (p != nullptr) {
      uwq_worker* w = new uwq_worker(this, p);
      assert(w != nullptr);

      ++uref_;
      p->worker = w;
      w->running_ = true;

      acquire(&p->lock);
      p->cpuid = mycpuid();
      addrun(p);
      release(&p->lock);

      for (int i = 0; i < NWORKERS; i++) {
        if (worker_[i] == nullptr)
          if (cmpxch(&worker_[i], (uwq_worker*)nullptr, w))
            return true;
      }
      panic("uwq::tryworker: oops");
    }
  }

  return false;
}

void
uwq::finish(void)
{
  bool gcnow = true;

  scoped_acquire lock0(&lock_);
  for (int i = 0; i < NWORKERS; i++) {
    if (worker_[i] != nullptr) {
      uwq_worker* w = worker_[i];
      gcnow = false;
      acquire(&w->lock_);
      cv_wakeup(&w->cv_);
      release(&w->lock_);
    }
  }

  if (gcnow)
    gc_delayed(this);
}

void
uwq::onzero() const
{
  uwq *u = (uwq*)this;
  u->finish();
}

void
uwq::setuentry(uptr uentry)
{
  uentry_ = uentry;
}

proc*
uwq::allocworker(void)
{
  uptr uentry = uentry_;

  if (uentry == 0)
    return nullptr;

  proc* p = proc::alloc();
  if (p == nullptr)
    return nullptr;
  safestrcpy(p->name, "uwq_worker", sizeof(p->name));

  // finishproc will drop these refs
  vmap_->incref();
  ftable_->incref();

  p->vmap = vmap_;
  p->ftable = ftable_;

  struct vmnode *vmn;
  if ((vmn = new vmnode(USTACKPAGES)) == nullptr) {
    finishproc(p);
    return nullptr;
  }

  // Include a bumper page
  uptr ustack = ustack_.fetch_add((USTACKPAGES*PGSIZE)+PGSIZE);
  uptr stacktop = ustack + (USTACKPAGES*PGSIZE);
  if (vmap_->insert(vmn, ustack, 1) < 0) {
    delete vmn;
    finishproc(p);
    return nullptr;
  }

  p->tf->rsp = stacktop - 8;
  p->tf->rip = uentry;
  p->tf->cs = UCSEG | 0x3;
  p->tf->ds = UDSEG | 0x3;
  p->tf->ss = p->tf->ds;
  p->tf->rflags = FL_IF;

  return p;
}
<commit_msg>Don't look<commit_after>#include "types.h"
#include "amd64.h"
#include "kernel.hh"
#include "cpu.hh"
#include "gc.hh"
#include "percpu.hh"
#include "spinlock.h"
#include "condvar.h"
#include "proc.hh"
#include "uwq.hh"
#include "vm.hh"
#include "kalloc.hh"
#include "bits.hh"
extern "C" {
#include "kern_c.h"
}

bool
uwq_trywork(void)
{
  // Returning true means uwq added a thread to the run queue

  u64 i, k;

  // A "random" victim CPU
  k = rdtsc();
  for (i = 0; i < NCPU; i++) {
    u64 j = (i+k) % NCPU;

    if (j == mycpuid())
      continue;
    struct cpu *c = &cpus[j];

    // The gc_epoch is for p and uwq
    scoped_gc_epoch xgc();
    barrier();

    struct proc *p = c->proc;
    if (p == nullptr)
      continue;
    uwq* uwq = p->uwq;
    if (uwq == nullptr)
      continue;

    if (uwq->haswork()) {
      if (uwq->tryworker())
        return true;
      break;
    }
  }

  return false;
}

long
sys_wqwait(void)
{
  uwq_worker* w = myproc()->worker;
  if (w == nullptr)
    return -1;

  return w->wait();
}

//
// uwq_worker
//
uwq_worker::uwq_worker(uwq* u, proc* p)
  : uwq_(u), proc_(p), running_(false)
{
  initlock(&lock_, "worker_lock", 0);
  initcondvar(&cv_, "worker_cv");
}

void
uwq_worker::exit(void)
{
  if (--uwq_->uref_ == 0)
    gc_delayed(uwq_);
  release(&lock_);
  delete this;
  ::exit();
}

long
uwq_worker::wait(void)
{
  acquire(&lock_);
  if (!uwq_->valid())
    this->exit();

  running_ = false;
  cv_sleep(&cv_, &lock_);

  if (!uwq_->valid())
    this->exit();
  release(&lock_);
  return 0;
}

//
// uwq
//
uwq*
uwq::alloc(vmap* vmap, filetable *ftable)
{
  uwq_ipcbuf* ipc;
  uwq* u;

  ipc = (uwq_ipcbuf*) ksalloc(slab_userwq);
  if (ipc == nullptr)
    return nullptr;

  ftable->incref();
  vmap->incref();

  u = new uwq(vmap, ftable, ipc);
  if (u == nullptr) {
    ftable->decref();
    vmap->decref();
    ksfree(slab_userwq, ipc);
    return nullptr;
  }

  if (mapkva(vmap->pml4, (char*)ipc, USERWQ, USERWQSIZE)) {
    ftable->decref();
    vmap->decref();
    ksfree(slab_userwq, ipc);
    u->dec();
    return nullptr;
  }

  return u;
}

uwq::uwq(vmap* vmap, filetable* ftable, uwq_ipcbuf* ipc)
  : rcu_freed("uwq"),
    vmap_(vmap), ftable_(ftable), ipc_(ipc),
    uentry_(0), ustack_(UWQSTACK), uref_(0)
{
  ftable_->incref();
  vmap_->incref();
  for (int i = 0; i < NCPU; i++)
    ipc_->len[i].v_ = 0;

  initlock(&lock_, "uwq_lock", 0);

  for (int i = 0; i < NWORKERS; i++)
    worker_[i].store(nullptr);
}

uwq::~uwq(void)
{
  if (ipc_ != nullptr)
    ksfree(slab_userwq, ipc_);
  vmap_->decref();
  ftable_->decref();
}

bool
uwq::haswork(void) const
{
  if (ipc_ == nullptr)
    return false;

  for (int i = 0; i < NCPU; i++) {
    if (ipc_->len[i].v_ > 0) {
      return true;
    }
  }
  return false;
}

bool
uwq::tryworker(void)
{
  if (!valid())
    return false;

  // Try to start a worker thread
  scoped_acquire lock0(&lock_);

  for (int i = 0; i < NWORKERS; i++) {
    if (worker_[i] == nullptr)
      continue;

    uwq_worker *w = worker_[i];
    if (w->running_)
      continue;
    else {
      scoped_acquire lock1(&w->lock_);
      proc* p = w->proc_;

      acquire(&p->lock);
      p->cpuid = mycpuid();
      release(&p->lock);

      w->running_ = true;
      cv_wakeup(&w->cv_);
      return true;
    }
  }
  lock0.release();

again:
  u64 uref = uref_.load();
  if (uref < ipc_->maxworkers) {
    if (!cmpxch(&uref_, uref, uref+1))
      goto again;
    // Guaranteed to have  slot in worker_

    proc* p = allocworker();
    if (p != nullptr) {
      uwq_worker* w = new uwq_worker(this, p);
      assert(w != nullptr);

      ++uref_;
      p->worker = w;
      w->running_ = true;

      acquire(&p->lock);
      p->cpuid = mycpuid();
      addrun(p);
      release(&p->lock);

      for (int i = 0; i < NWORKERS; i++) {
        if (worker_[i] == nullptr)
          if (cmpxch(&worker_[i], (uwq_worker*)nullptr, w))
            return true;
      }
      panic("uwq::tryworker: oops");
    }
  }

  return false;
}

void
uwq::finish(void)
{
  bool gcnow = true;

  scoped_acquire lock0(&lock_);
  for (int i = 0; i < NWORKERS; i++) {
    if (worker_[i] != nullptr) {
      uwq_worker* w = worker_[i];
      gcnow = false;
      acquire(&w->lock_);
      cv_wakeup(&w->cv_);
      release(&w->lock_);
    }
  }

  if (gcnow)
    gc_delayed(this);
}

void
uwq::onzero() const
{
  uwq *u = (uwq*)this;
  u->finish();
}

void
uwq::setuentry(uptr uentry)
{
  uentry_ = uentry;
}

proc*
uwq::allocworker(void)
{
  uptr uentry = uentry_;

  if (uentry == 0)
    return nullptr;

  proc* p = proc::alloc();
  if (p == nullptr)
    return nullptr;
  safestrcpy(p->name, "uwq_worker", sizeof(p->name));

  // finishproc will drop these refs
  vmap_->incref();
  ftable_->incref();

  p->vmap = vmap_;
  p->ftable = ftable_;

  struct vmnode *vmn;
  if ((vmn = new vmnode(USTACKPAGES)) == nullptr) {
    finishproc(p);
    return nullptr;
  }

  // Include a bumper page
  uptr ustack = ustack_.fetch_add((USTACKPAGES*PGSIZE)+PGSIZE);
  uptr stacktop = ustack + (USTACKPAGES*PGSIZE);
  if (vmap_->insert(vmn, ustack, 1) < 0) {
    delete vmn;
    finishproc(p);
    return nullptr;
  }

  p->tf->rsp = stacktop - 8;
  p->tf->rip = uentry;
  p->tf->cs = UCSEG | 0x3;
  p->tf->ds = UDSEG | 0x3;
  p->tf->ss = p->tf->ds;
  p->tf->rflags = FL_IF;

  return p;
}
<|endoftext|>


<commit_before>#include "spacetyper/scalablesprite.h"

#include <cassert>
#include <iostream>
#include <algorithm>

#include "spacetyper/vao.h"
#include "spacetyper/rect.h"
#include "spacetyper/texture.h"
#include "spacetyper/texturecache.h"

#include "scalingsprite.pb.h"
#include "spacetyper/proto.h"

////////////////////////////////////////////////////////////////////////////////

class ScalableSpriteData {
 public:
  ScalableSpriteData(const VaoBuilder& avao, const glm::vec2& aworld_size, const glm::vec2& aclient_size, const glm::vec2& aclient_offset)
      : vao(avao), world_size(aworld_size), client_size(aclient_size), client_offset(aclient_offset) {}
  Vao vao;
  glm::vec2 world_size;
  glm::vec2 client_size;
  glm::vec2 client_offset;
};

////////////////////////////////////////////////////////////////////////////////

ScalableSprite::ScalableSprite(Texture2d* texture, const glm::vec2& min_size, SizeType size_type, const glm::vec2& size)
  : texture_(texture)
  , min_size_(min_size)
  , size_type_(size_type)
  , size_(size)
{
}

ScalableSprite::~ScalableSprite() {
}

void ScalableSprite::SetClientSize(const glm::vec2 &new_size) {
  assert(this);
  SetSizeSub(new_size, SizeType::CLIENT);
}

const glm::vec2 ScalableSprite::GetClientSize() const {
  assert(this);
  if( size_type_ == SizeType::CLIENT) return size_;
  PrepareData();
  return data_->client_size;
}

const glm::vec2 ScalableSprite::GetClientOffset() const {
  assert(this);
  PrepareData();
  return data_->client_offset;
}

void ScalableSprite::SetSize(const glm::vec2 &new_size) {
  assert(this);
  SetSizeSub(new_size, SizeType::WORLD);
}

const glm::vec2 ScalableSprite::GetSize() const {
  assert(this);
  if( size_type_ == SizeType::WORLD) return size_;
  PrepareData();
  return data_->world_size;
}

const glm::vec2 ScalableSprite::GetMinimumSize() const {
  assert(this);
  return min_size_;
}

const glm::vec2 ScalableSprite::GetMinimumSize(const glm::vec2& extra) const {
  assert(this);
  return glm::vec2(min_size_.x + extra.x, min_size_.y + extra.y);
}

const Texture2d* ScalableSprite::texture_ptr() const {
  assert(this);
  return texture_;
}

const Vao* ScalableSprite::vao_ptr() const {
  assert(this);
  PrepareData();
  return &data_->vao;
}

std::pair<ScalableSprite::SizeType, glm::vec2> ScalableSprite::GetSizeData() const {
  return std::pair<SizeType, glm::vec2>(size_type_, size_);
};

void ScalableSprite::PrepareData() const {
  assert(this);
  if( data_.get() == nullptr) {
    data_.reset(BuildData());
  }
}

void ScalableSprite::SetSizeSub(const glm::vec2& new_size, SizeType type) {
  assert(this);
  if( data_.get() != nullptr && size_type_ == type && size_ == new_size) {
    // if we have built the data and the size & type is the same
    // then there's no need to rebuild it
    return;
  }
  size_ = new_size;
  size_type_ = type;
  data_.reset();
}

////////////////////////////////////////////////////////////////////////////////

namespace {
  glm::vec2 DetermineSize(const glm::vec2 real_size, Rect<int> pixel_data) {
    return glm::vec2( real_size.x - pixel_data.GetWidth() , real_size.y - pixel_data.GetHeight());
  }

  VaoBuilder BuildNinepatchVao(const Texture2d* texture_, const Rect<int> draw, const glm::vec2& inner_size_) {
    VaoBuilder data;

    // 00     10                20     30
    // +------+-----------------+------+
    // |      |                 |      |
    // |01    |11               |21    | 31
    // +------+-----------------+------+
    // |      |                 |      |
    // |      |                 |      |
    // |      |                 |      |
    // |      |                 |      |
    // |      |                 |      |
    // |      |                 |      |
    // |02    |12               |22    | 32
    // +------+-----------------+------+
    // |      |                 |      |
    // |03    |13               |23    | 33
    // +------+-----------------+------+
    //
    const float width = texture_->width();
    const float height = texture_->height();

    const float border_left = std::max(0, draw.left);
    const float border_right = std::max(0.0f, width - draw.right);
    const float border_top = std::max(0, draw.top);
    const float border_bottom = std::max(0.0f, height - draw.bottom);

    const float x0 = 0.0f;
    const float x1 = border_left;
    const float x2 = x1 + inner_size_.x;
    const float x3 = x2 + border_right;

    const float y0 = 0.0f;
    const float y1 = border_top;
    const float y2 = y1 + inner_size_.y;
    const float y3 = y2 + border_bottom;

    const float u0 = 0.0f;
    const float u1 = 0.0f + border_left / width;
    const float u2 = 1.0f - border_right/width;
    const float u3 = 1.0f;

    const float v0 = 0.0f;
    const float v1 = 0.0f + border_top / height;
    const float v2 = 1.0f - border_bottom / height;
    const float v3 = 1.0f;

  #define P(A, B) Point(x ## A, y ## B, u ## A, v ## B)
    data.quad(P(0,0), P(1,0), P(0,1), P(1,1))
        .quad(P(1,0), P(2,0), P(1,1), P(2,1))
        .quad(P(2,0), P(3,0), P(2,1), P(3,1));
    data.quad(P(0,1), P(1,1), P(0,2), P(1,2))
        .quad(P(1,1), P(2,1), P(1,2), P(2,2))
        .quad(P(2,1), P(3,1), P(2,2), P(3,2));
    data.quad(P(0,2), P(1,2), P(0,3), P(1,3))
        .quad(P(1,2), P(2,2), P(1,3), P(2,3))
        .quad(P(2,2), P(3,2), P(2,3), P(3,3));

    // basic scale - like a sprite
    // data.quad(P(0,0), P(3,0), P(0,3), P(3,3));
  #undef P

    return data;
  }
}

class ScalableSpriteNinepatch : public ScalableSprite {
 public:
  ScalableSpriteNinepatch(Texture2d* texture, SizeType size_type, const glm::vec2& size, const Rect<int>& da, const Rect<int>& ca)
      : ScalableSprite(texture, glm::vec2(ca.GetWidth(), ca.GetHeight()), size_type, size)
      , draw_area_(da), client_area_(ca) {}

  glm::vec2 DetermineRealSize() const {
    auto data = GetSizeData();
    const auto size = data.second;
    switch (data.first) {
      case ScalableSprite::SizeType::CLIENT:
        return glm::vec2(size.x + client_area_.GetWidth(), size.y + client_area_.GetHeight());
      case ScalableSprite::SizeType::WORLD:
        return size;
    }
    assert(false && "unhandled SizeType");
  }

  bool ValidateCalculatedSize(const glm::vec2& real_size, const glm::vec2& client_size) const {
    auto data = GetSizeData();
    const auto size = data.second;
    switch (data.first) {
      case ScalableSprite::SizeType::CLIENT:
        return client_size == size;
      case ScalableSprite::SizeType::WORLD:
        return real_size == size;
    }
    assert(false && "unhandled SizeType");
  }

  ScalableSpriteData* BuildData() const override {
    const glm::vec2 real_size = DetermineRealSize();
    const glm::vec2 draw_size = DetermineSize(real_size, draw_area_);
    const glm::vec2 client_size = DetermineSize(real_size, client_area_);

    assert(ValidateCalculatedSize(real_size, client_size));

    return new ScalableSpriteData(BuildNinepatchVao(texture_ptr(), draw_area_, draw_size), real_size, client_size, glm::vec2(client_area_.left, client_area_.top));
  }

  Rect<int> draw_area_;
  Rect<int> client_area_;
};

////////////////////////////////////////////////////////////////////////////////

Rect<int> Convert(const scalingsprite::Rect& r) {
  return Rect<int>::FromLeftRightTopBottom(r.left(), r.right(), r.top(), r.bottom());
}

std::shared_ptr<ScalableSprite> LoadScalableNinepatch(Texture2d* tex, ScalableSprite::SizeType size_type, glm::vec2 size, const scalingsprite::Ninepatch& data) {
  std::shared_ptr<ScalableSprite> ret ( new ScalableSpriteNinepatch(tex, size_type, size, Convert(data.draw()), Convert(data.client())) );
  return ret;
}

std::shared_ptr<ScalableSprite> LoadScalableSprite(const std::string& path, const glm::vec2& size, TextureCache* cache) {
  std::string json_path = path + ".json";
  Texture2d* tex = cache->GetTexture(path);
  const ScalableSprite::SizeType size_type = ScalableSprite::SizeType::WORLD;

  scalingsprite::ScalingSprite sprite;
  SaveProtoJson(sprite, path+".json");
  SaveProtoJson(sprite, path+".txt");

  // only ninepatch supported...
  assert(sprite.has_ninepatch());
  return LoadScalableNinepatch(tex, size_type, size, sprite.ninepatch());
}

<commit_msg>added sprite loading<commit_after>#include "spacetyper/scalablesprite.h"

#include <cassert>
#include <iostream>
#include <algorithm>

#include "spacetyper/vao.h"
#include "spacetyper/rect.h"
#include "spacetyper/texture.h"
#include "spacetyper/texturecache.h"

#include "scalingsprite.pb.h"
#include "spacetyper/proto.h"

////////////////////////////////////////////////////////////////////////////////

class ScalableSpriteData {
 public:
  ScalableSpriteData(const VaoBuilder& avao, const glm::vec2& aworld_size, const glm::vec2& aclient_size, const glm::vec2& aclient_offset)
      : vao(avao), world_size(aworld_size), client_size(aclient_size), client_offset(aclient_offset) {}
  Vao vao;
  glm::vec2 world_size;
  glm::vec2 client_size;
  glm::vec2 client_offset;
};

////////////////////////////////////////////////////////////////////////////////

ScalableSprite::ScalableSprite(Texture2d* texture, const glm::vec2& min_size, SizeType size_type, const glm::vec2& size)
  : texture_(texture)
  , min_size_(min_size)
  , size_type_(size_type)
  , size_(size)
{
}

ScalableSprite::~ScalableSprite() {
}

void ScalableSprite::SetClientSize(const glm::vec2 &new_size) {
  assert(this);
  SetSizeSub(new_size, SizeType::CLIENT);
}

const glm::vec2 ScalableSprite::GetClientSize() const {
  assert(this);
  if( size_type_ == SizeType::CLIENT) return size_;
  PrepareData();
  return data_->client_size;
}

const glm::vec2 ScalableSprite::GetClientOffset() const {
  assert(this);
  PrepareData();
  return data_->client_offset;
}

void ScalableSprite::SetSize(const glm::vec2 &new_size) {
  assert(this);
  SetSizeSub(new_size, SizeType::WORLD);
}

const glm::vec2 ScalableSprite::GetSize() const {
  assert(this);
  if( size_type_ == SizeType::WORLD) return size_;
  PrepareData();
  return data_->world_size;
}

const glm::vec2 ScalableSprite::GetMinimumSize() const {
  assert(this);
  return min_size_;
}

const glm::vec2 ScalableSprite::GetMinimumSize(const glm::vec2& extra) const {
  assert(this);
  return glm::vec2(min_size_.x + extra.x, min_size_.y + extra.y);
}

const Texture2d* ScalableSprite::texture_ptr() const {
  assert(this);
  return texture_;
}

const Vao* ScalableSprite::vao_ptr() const {
  assert(this);
  PrepareData();
  return &data_->vao;
}

std::pair<ScalableSprite::SizeType, glm::vec2> ScalableSprite::GetSizeData() const {
  return std::pair<SizeType, glm::vec2>(size_type_, size_);
};

void ScalableSprite::PrepareData() const {
  assert(this);
  if( data_.get() == nullptr) {
    data_.reset(BuildData());
  }
}

void ScalableSprite::SetSizeSub(const glm::vec2& new_size, SizeType type) {
  assert(this);
  if( data_.get() != nullptr && size_type_ == type && size_ == new_size) {
    // if we have built the data and the size & type is the same
    // then there's no need to rebuild it
    return;
  }
  size_ = new_size;
  size_type_ = type;
  data_.reset();
}

////////////////////////////////////////////////////////////////////////////////

namespace {
  glm::vec2 DetermineSize(const glm::vec2 real_size, Rect<int> pixel_data) {
    return glm::vec2( real_size.x - pixel_data.GetWidth() , real_size.y - pixel_data.GetHeight());
  }

  VaoBuilder BuildNinepatchVao(const Texture2d* texture_, const Rect<int> draw, const glm::vec2& inner_size_) {
    VaoBuilder data;

    // 00     10                20     30
    // +------+-----------------+------+
    // |      |                 |      |
    // |01    |11               |21    | 31
    // +------+-----------------+------+
    // |      |                 |      |
    // |      |                 |      |
    // |      |                 |      |
    // |      |                 |      |
    // |      |                 |      |
    // |      |                 |      |
    // |02    |12               |22    | 32
    // +------+-----------------+------+
    // |      |                 |      |
    // |03    |13               |23    | 33
    // +------+-----------------+------+
    //
    const float width = texture_->width();
    const float height = texture_->height();

    const float border_left = std::max(0, draw.left);
    const float border_right = std::max(0.0f, width - draw.right);
    const float border_top = std::max(0, draw.top);
    const float border_bottom = std::max(0.0f, height - draw.bottom);

    const float x0 = 0.0f;
    const float x1 = border_left;
    const float x2 = x1 + inner_size_.x;
    const float x3 = x2 + border_right;

    const float y0 = 0.0f;
    const float y1 = border_top;
    const float y2 = y1 + inner_size_.y;
    const float y3 = y2 + border_bottom;

    const float u0 = 0.0f;
    const float u1 = 0.0f + border_left / width;
    const float u2 = 1.0f - border_right/width;
    const float u3 = 1.0f;

    const float v0 = 0.0f;
    const float v1 = 0.0f + border_top / height;
    const float v2 = 1.0f - border_bottom / height;
    const float v3 = 1.0f;

  #define P(A, B) Point(x ## A, y ## B, u ## A, v ## B)
    data.quad(P(0,0), P(1,0), P(0,1), P(1,1))
        .quad(P(1,0), P(2,0), P(1,1), P(2,1))
        .quad(P(2,0), P(3,0), P(2,1), P(3,1));
    data.quad(P(0,1), P(1,1), P(0,2), P(1,2))
        .quad(P(1,1), P(2,1), P(1,2), P(2,2))
        .quad(P(2,1), P(3,1), P(2,2), P(3,2));
    data.quad(P(0,2), P(1,2), P(0,3), P(1,3))
        .quad(P(1,2), P(2,2), P(1,3), P(2,3))
        .quad(P(2,2), P(3,2), P(2,3), P(3,3));

    // basic scale - like a sprite
    // data.quad(P(0,0), P(3,0), P(0,3), P(3,3));
  #undef P

    return data;
  }
}

class ScalableSpriteNinepatch : public ScalableSprite {
 public:
  ScalableSpriteNinepatch(Texture2d* texture, SizeType size_type, const glm::vec2& size, const Rect<int>& da, const Rect<int>& ca)
      : ScalableSprite(texture, glm::vec2(ca.GetWidth(), ca.GetHeight()), size_type, size)
      , draw_area_(da), client_area_(ca) {}

  glm::vec2 DetermineRealSize() const {
    auto data = GetSizeData();
    const auto size = data.second;
    switch (data.first) {
      case ScalableSprite::SizeType::CLIENT:
        return glm::vec2(size.x + client_area_.GetWidth(), size.y + client_area_.GetHeight());
      case ScalableSprite::SizeType::WORLD:
        return size;
    }
    assert(false && "unhandled SizeType");
  }

  bool ValidateCalculatedSize(const glm::vec2& real_size, const glm::vec2& client_size) const {
    auto data = GetSizeData();
    const auto size = data.second;
    switch (data.first) {
      case ScalableSprite::SizeType::CLIENT:
        return client_size == size;
      case ScalableSprite::SizeType::WORLD:
        return real_size == size;
    }
    assert(false && "unhandled SizeType");
  }

  ScalableSpriteData* BuildData() const override {
    const glm::vec2 real_size = DetermineRealSize();
    const glm::vec2 draw_size = DetermineSize(real_size, draw_area_);
    const glm::vec2 client_size = DetermineSize(real_size, client_area_);

    assert(ValidateCalculatedSize(real_size, client_size));

    return new ScalableSpriteData(BuildNinepatchVao(texture_ptr(), draw_area_, draw_size), real_size, client_size, glm::vec2(client_area_.left, client_area_.top));
  }

  Rect<int> draw_area_;
  Rect<int> client_area_;
};

////////////////////////////////////////////////////////////////////////////////

Rect<int> Convert(const scalingsprite::Rect& r) {
  return Rect<int>::FromLeftRightTopBottom(r.left(), r.right(), r.top(), r.bottom());
}

std::shared_ptr<ScalableSprite> LoadScalableNinepatch(Texture2d* tex, ScalableSprite::SizeType size_type, glm::vec2 size, const scalingsprite::Ninepatch& data) {
  std::shared_ptr<ScalableSprite> ret ( new ScalableSpriteNinepatch(tex, size_type, size, Convert(data.draw()), Convert(data.client())) );
  return ret;
}

std::shared_ptr<ScalableSprite> LoadScalableSprite(const std::string& path, const glm::vec2& size, TextureCache* cache) {
  Texture2d* tex = cache->GetTexture(path);
  const ScalableSprite::SizeType size_type = ScalableSprite::SizeType::WORLD;

  scalingsprite::ScalingSprite sprite;
  LoadProtoText(&sprite, path+".txt");

  // only ninepatch supported...
  assert(sprite.has_ninepatch());
  return LoadScalableNinepatch(tex, size_type, size, sprite.ninepatch());
}

<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_background_scrub.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2018,2019                        */
/* [+] 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                                                     */
<commit_msg>Added p9_mss_memdiag for cronus ipl and modified scrub for step 16<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_background_scrub.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2018,2019                        */
/* [+] 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_mss_background_scrub.H
/// @brief Begin background scrub
///
// *HWP HWP Owner: Matt Hickman <Matthew.Hickman@ibm.com>
// *HWP FW Owner: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#ifndef __P9_MSS_BACKGROUND_SCRUB__
#define __P9_MSS_BACKGROUND_SCRUB__

#include <fapi2.H>

typedef fapi2::ReturnCode (*p9_mss_background_scrub_FP_t) (const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>&);

extern "C"
{

    ///
    /// @brief Begin background scrub
    /// @param[in] i_target, MCBIST
    /// @return FAPI2_RC_SUCCESS iff ok
    ///
    fapi2::ReturnCode p9_mss_background_scrub( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );

}

#endif
<|endoftext|>