{
  LossLayer<Dtype>::LayerSetUp(bottom, top);
  LayerParameter softmax_param(this->layer_param_);
  softmax_param.set_type("Softmax");
  softmax_layer_ = LayerRegistry<Dtype>::CreateLayer(softmax_param);

#include <algorithm>
#include <cfloat>
#include <vector>

#include "caffe/layers/softmax_loss_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::LayerSetUp(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top)

  softmax_bottom_vec_.clear();
  softmax_bottom_vec_.push_back(bottom[0]);
  softmax_top_vec_.clear();
  softmax_top_vec_.push_back(&prob_);
  softmax_layer_->SetUp(softmax_bottom_vec_, softmax_top_vec_);

  /*has_ignore_label_ =
    this->layer_param_.loss_param().has_ignore_label();
  if (has_ignore_label_) {
    ignore_label_ = this->layer_param_.loss_param().ignore_label();
  }*/

  if (!this->layer_param_.loss_param().has_normalization() &&
      this->layer_param_.loss_param().has_normalize()) {
    normalization_ = this->layer_param_.loss_param().normalize() ?
                     LossParameter_NormalizationMode_VALID :
                     LossParameter_NormalizationMode_BATCH_SIZE;
  } else {
    normalization_ = this->layer_param_.loss_param().normalization();
  }
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Reshape(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  LossLayer<Dtype>::Reshape(bottom, top);
  softmax_layer_->Reshape(softmax_bottom_vec_, softmax_top_vec_);
  softmax_axis_ =
      bottom[0]->CanonicalAxisIndex(this->layer_param_.softmax_param().axis());
  outer_num_ = bottom[0]->count(0, softmax_axis_);
  inner_num_ = bottom[0]->count(softmax_axis_ + 1);
  CHECK_EQ(outer_num_ * inner_num_, bottom[1]->count())
      << "Number of labels must match number of predictions; "
      << "e.g., if softmax axis == 1 and prediction shape is (N, C, H, W), "
      << "label count (number of labels) must be N*H*W, "
      << "with integer values in {0, 1, ..., C-1}.";
  if (top.size() >= 2) {
    // softmax output
    top[1]->ReshapeLike(*bottom[0]);
  }

  if (this->layer_param_.loss_param().has_label_start())
      label_start_ = this->layer_param_.loss_param().label_start();
  else
      label_start_ = 0;

  if (this->layer_param_.loss_param().has_label_end())
      label_end_ = this->layer_param_.loss_param().label_end();
  else
      label_end_ = prob_.shape(softmax_axis_) - 1;

  static bool not_first_time = 0;
  if (!not_first_time) {
      LOG(INFO) << "valid label value range: [" << label_start_ << ',' << label_end_
          << "], number of classes = " << prob_.shape(softmax_axis_)
          << ", normalization mode = " << normalization_;
      not_first_time = true;
  }

  CHECK_EQ(label_end_ - label_start_ + 1, prob_.shape(softmax_axis_))
      << "valid label count must match the number of predicted classes";
}

template <typename Dtype>
Dtype SoftmaxWithLossLayer<Dtype>::get_normalizer(
    LossParameter_NormalizationMode normalization_mode, int valid_count) {
  Dtype normalizer;
  switch (normalization_mode) {
    case LossParameter_NormalizationMode_FULL:
      normalizer = Dtype(outer_num_ * inner_num_);
      break;
    case LossParameter_NormalizationMode_VALID:
      if (valid_count == -1) {
        normalizer = Dtype(outer_num_ * inner_num_);
      } else {
        normalizer = Dtype(valid_count);
      }
      break;
    case LossParameter_NormalizationMode_BATCH_SIZE:
      normalizer = Dtype(outer_num_);
      break;
    case LossParameter_NormalizationMode_NONE:
      normalizer = Dtype(1);
      break;
    default:
      LOG(FATAL) << "Unknown normalization mode: "
          << LossParameter_NormalizationMode_Name(normalization_mode);
  }
  // Some users will have no labels for some examples in order to 'turn off' a
  // particular loss in a multi-task setup. The max prevents NaNs in that case.
  return std::max(Dtype(1.0), normalizer);
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Forward_cpu(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  // The forward pass computes the softmax prob values.
  softmax_layer_->Forward(softmax_bottom_vec_, softmax_top_vec_);
  const Dtype* prob_data = prob_.cpu_data();
  const Dtype* label = bottom[1]->cpu_data();
  int dim = prob_.count() / outer_num_;
  int count = 0;
  Dtype loss = 0;
  for (int i = 0; i < outer_num_; ++i) {
    for (int j = 0; j < inner_num_; j++) {
      int label_value = static_cast<int>(label[i * inner_num_ + j]);
      /*if (has_ignore_label_ && label_value == ignore_label_) {
        continue;
      }*/
      if (label_value < label_start_ || label_value > label_end_)
          continue;
      label_value -= label_start_;
      DCHECK_GE(label_value, 0);
      DCHECK_LT(label_value, prob_.shape(softmax_axis_));
      loss -= log(std::max(prob_data[i * dim + label_value * inner_num_ + j],
                           Dtype(FLT_MIN)));
      ++count;
    }
  }
  top[0]->mutable_cpu_data()[0] = loss / get_normalizer(normalization_, count);
  if (top.size() == 2) {
    top[1]->ShareData(prob_);
  }
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
  if (propagate_down[1]) {
    LOG(FATAL) << this->type()
               << " Layer cannot backpropagate to label inputs.";
  }
  if (propagate_down[0]) {
    Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
    const Dtype* prob_data = prob_.cpu_data();
    caffe_copy(prob_.count(), prob_data, bottom_diff);
    const Dtype* label = bottom[1]->cpu_data();
    int dim = prob_.count() / outer_num_;
    int count = 0;
    for (int i = 0; i < outer_num_; ++i) {
      for (int j = 0; j < inner_num_; ++j) {
        const int label_value = static_cast<int>(label[i * inner_num_ + j]);
        if (label_value < label_start_ || label_value > label_end_) {
          for (int c = 0; c < bottom[0]->shape(softmax_axis_); ++c) {
            bottom_diff[i * dim + c * inner_num_ + j] = 0;
          }
        } else {
          bottom_diff[i * dim + (label_value - label_start_) * inner_num_ + j] -= 1;
          ++count;
        }
      }
    }
    // Scale gradient
    Dtype loss_weight = top[0]->cpu_diff()[0] /
                        get_normalizer(normalization_, count);
    caffe_scal(prob_.count(), loss_weight, bottom_diff);
  }
}

#ifdef CPU_ONLY
STUB_GPU(SoftmaxWithLossLayer);
#endif

INSTANTIATE_CLASS(SoftmaxWithLossLayer);
REGISTER_LAYER_CLASS(SoftmaxWithLoss);

}  // namespace caffe


softmax_bottom_vec_.clear();
  softmax_bottom_vec_.push_back(bottom[0]);
  softmax_top_vec_.clear();
  softmax_top_vec_.push_back(&prob_);

#include <algorithm>
#include <cfloat>
#include <vector>

#include "caffe/layers/softmax_loss_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::LayerSetUp(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  LossLayer<Dtype>::LayerSetUp(bottom, top);
  LayerParameter softmax_param(this->layer_param_);
  softmax_param.set_type("Softmax");
  softmax_layer_ = LayerRegistry<Dtype>::CreateLayer(softmax_param);

  softmax_layer_->SetUp(softmax_bottom_vec_, softmax_top_vec_);

  /*has_ignore_label_ =
    this->layer_param_.loss_param().has_ignore_label();
  if (has_ignore_label_) {
    ignore_label_ = this->layer_param_.loss_param().ignore_label();
  }*/

  if (!this->layer_param_.loss_param().has_normalization() &&
      this->layer_param_.loss_param().has_normalize()) {
    normalization_ = this->layer_param_.loss_param().normalize() ?
                     LossParameter_NormalizationMode_VALID :
                     LossParameter_NormalizationMode_BATCH_SIZE;
  } else {
    normalization_ = this->layer_param_.loss_param().normalization();
  }
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Reshape(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  LossLayer<Dtype>::Reshape(bottom, top);
  softmax_layer_->Reshape(softmax_bottom_vec_, softmax_top_vec_);
  softmax_axis_ =
      bottom[0]->CanonicalAxisIndex(this->layer_param_.softmax_param().axis());
  outer_num_ = bottom[0]->count(0, softmax_axis_);
  inner_num_ = bottom[0]->count(softmax_axis_ + 1);
  CHECK_EQ(outer_num_ * inner_num_, bottom[1]->count())
      << "Number of labels must match number of predictions; "
      << "e.g., if softmax axis == 1 and prediction shape is (N, C, H, W), "
      << "label count (number of labels) must be N*H*W, "
      << "with integer values in {0, 1, ..., C-1}.";
  if (top.size() >= 2) {
    // softmax output
    top[1]->ReshapeLike(*bottom[0]);
  }

  if (this->layer_param_.loss_param().has_label_start())
      label_start_ = this->layer_param_.loss_param().label_start();
  else
      label_start_ = 0;

  if (this->layer_param_.loss_param().has_label_end())
      label_end_ = this->layer_param_.loss_param().label_end();
  else
      label_end_ = prob_.shape(softmax_axis_) - 1;

  static bool not_first_time = 0;
  if (!not_first_time) {
      LOG(INFO) << "valid label value range: [" << label_start_ << ',' << label_end_
          << "], number of classes = " << prob_.shape(softmax_axis_)
          << ", normalization mode = " << normalization_;
      not_first_time = true;
  }

  CHECK_EQ(label_end_ - label_start_ + 1, prob_.shape(softmax_axis_))
      << "valid label count must match the number of predicted classes";
}

template <typename Dtype>
Dtype SoftmaxWithLossLayer<Dtype>::get_normalizer(
    LossParameter_NormalizationMode normalization_mode, int valid_count) {
  Dtype normalizer;
  switch (normalization_mode) {
    case LossParameter_NormalizationMode_FULL:
      normalizer = Dtype(outer_num_ * inner_num_);
      break;
    case LossParameter_NormalizationMode_VALID:
      if (valid_count == -1) {
        normalizer = Dtype(outer_num_ * inner_num_);
      } else {
        normalizer = Dtype(valid_count);
      }
      break;
    case LossParameter_NormalizationMode_BATCH_SIZE:
      normalizer = Dtype(outer_num_);
      break;
    case LossParameter_NormalizationMode_NONE:
      normalizer = Dtype(1);
      break;
    default:
      LOG(FATAL) << "Unknown normalization mode: "
          << LossParameter_NormalizationMode_Name(normalization_mode);
  }
  // Some users will have no labels for some examples in order to 'turn off' a
  // particular loss in a multi-task setup. The max prevents NaNs in that case.
  return std::max(Dtype(1.0), normalizer);
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Forward_cpu(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  // The forward pass computes the softmax prob values.
  softmax_layer_->Forward(softmax_bottom_vec_, softmax_top_vec_);
  const Dtype* prob_data = prob_.cpu_data();
  const Dtype* label = bottom[1]->cpu_data();
  int dim = prob_.count() / outer_num_;
  int count = 0;
  Dtype loss = 0;
  for (int i = 0; i < outer_num_; ++i) {
    for (int j = 0; j < inner_num_; j++) {
      int label_value = static_cast<int>(label[i * inner_num_ + j]);
      /*if (has_ignore_label_ && label_value == ignore_label_) {
        continue;
      }*/
      if (label_value < label_start_ || label_value > label_end_)
          continue;
      label_value -= label_start_;
      DCHECK_GE(label_value, 0);
      DCHECK_LT(label_value, prob_.shape(softmax_axis_));
      loss -= log(std::max(prob_data[i * dim + label_value * inner_num_ + j],
                           Dtype(FLT_MIN)));
      ++count;
    }
  }
  top[0]->mutable_cpu_data()[0] = loss / get_normalizer(normalization_, count);
  if (top.size() == 2) {
    top[1]->ShareData(prob_);
  }
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
  if (propagate_down[1]) {
    LOG(FATAL) << this->type()
               << " Layer cannot backpropagate to label inputs.";
  }
  if (propagate_down[0]) {
    Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
    const Dtype* prob_data = prob_.cpu_data();
    caffe_copy(prob_.count(), prob_data, bottom_diff);
    const Dtype* label = bottom[1]->cpu_data();
    int dim = prob_.count() / outer_num_;
    int count = 0;
    for (int i = 0; i < outer_num_; ++i) {
      for (int j = 0; j < inner_num_; ++j) {
        const int label_value = static_cast<int>(label[i * inner_num_ + j]);
        if (label_value < label_start_ || label_value > label_end_) {
          for (int c = 0; c < bottom[0]->shape(softmax_axis_); ++c) {
            bottom_diff[i * dim + c * inner_num_ + j] = 0;
          }
        } else {
          bottom_diff[i * dim + (label_value - label_start_) * inner_num_ + j] -= 1;
          ++count;
        }
      }
    }
    // Scale gradient
    Dtype loss_weight = top[0]->cpu_diff()[0] /
                        get_normalizer(normalization_, count);
    caffe_scal(prob_.count(), loss_weight, bottom_diff);
  }
}

#ifdef CPU_ONLY
STUB_GPU(SoftmaxWithLossLayer);
#endif

INSTANTIATE_CLASS(SoftmaxWithLossLayer);
REGISTER_LAYER_CLASS(SoftmaxWithLoss);

}  // namespace caffe


softmax_layer_->SetUp(softmax_bottom_vec_, softmax_top_vec_);

  /*has_ignore_label_ =
    this->layer_param_.loss_param().has_ignore_label();
  if (has_ignore_label_) {
    ignore_label_ = this->layer_param_.loss_param().ignore_label();
  }*/

  if (!this->layer_param_.loss_param().has_normalization() &&
      this->layer_param_.loss_param().has_normalize()) {
    normalization_ = this->layer_param_.loss_param().normalize() ?
                     LossParameter_NormalizationMode_VALID :
                     LossParameter_NormalizationMode_BATCH_SIZE;
  } else {
    normalization_ = this->layer_param_.loss_param().normalization();
  }
}

#include <algorithm>
#include <cfloat>
#include <vector>

#include "caffe/layers/softmax_loss_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::LayerSetUp(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  LossLayer<Dtype>::LayerSetUp(bottom, top);
  LayerParameter softmax_param(this->layer_param_);
  softmax_param.set_type("Softmax");
  softmax_layer_ = LayerRegistry<Dtype>::CreateLayer(softmax_param);
  softmax_bottom_vec_.clear();
  softmax_bottom_vec_.push_back(bottom[0]);
  softmax_top_vec_.clear();
  softmax_top_vec_.push_back(&prob_);

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Reshape(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  LossLayer<Dtype>::Reshape(bottom, top);
  softmax_layer_->Reshape(softmax_bottom_vec_, softmax_top_vec_);
  softmax_axis_ =
      bottom[0]->CanonicalAxisIndex(this->layer_param_.softmax_param().axis());
  outer_num_ = bottom[0]->count(0, softmax_axis_);
  inner_num_ = bottom[0]->count(softmax_axis_ + 1);
  CHECK_EQ(outer_num_ * inner_num_, bottom[1]->count())
      << "Number of labels must match number of predictions; "
      << "e.g., if softmax axis == 1 and prediction shape is (N, C, H, W), "
      << "label count (number of labels) must be N*H*W, "
      << "with integer values in {0, 1, ..., C-1}.";
  if (top.size() >= 2) {
    // softmax output
    top[1]->ReshapeLike(*bottom[0]);
  }

  if (this->layer_param_.loss_param().has_label_start())
      label_start_ = this->layer_param_.loss_param().label_start();
  else
      label_start_ = 0;

  if (this->layer_param_.loss_param().has_label_end())
      label_end_ = this->layer_param_.loss_param().label_end();
  else
      label_end_ = prob_.shape(softmax_axis_) - 1;

  static bool not_first_time = 0;
  if (!not_first_time) {
      LOG(INFO) << "valid label value range: [" << label_start_ << ',' << label_end_
          << "], number of classes = " << prob_.shape(softmax_axis_)
          << ", normalization mode = " << normalization_;
      not_first_time = true;
  }

  CHECK_EQ(label_end_ - label_start_ + 1, prob_.shape(softmax_axis_))
      << "valid label count must match the number of predicted classes";
}

template <typename Dtype>
Dtype SoftmaxWithLossLayer<Dtype>::get_normalizer(
    LossParameter_NormalizationMode normalization_mode, int valid_count) {
  Dtype normalizer;
  switch (normalization_mode) {
    case LossParameter_NormalizationMode_FULL:
      normalizer = Dtype(outer_num_ * inner_num_);
      break;
    case LossParameter_NormalizationMode_VALID:
      if (valid_count == -1) {
        normalizer = Dtype(outer_num_ * inner_num_);
      } else {
        normalizer = Dtype(valid_count);
      }
      break;
    case LossParameter_NormalizationMode_BATCH_SIZE:
      normalizer = Dtype(outer_num_);
      break;
    case LossParameter_NormalizationMode_NONE:
      normalizer = Dtype(1);
      break;
    default:
      LOG(FATAL) << "Unknown normalization mode: "
          << LossParameter_NormalizationMode_Name(normalization_mode);
  }
  // Some users will have no labels for some examples in order to 'turn off' a
  // particular loss in a multi-task setup. The max prevents NaNs in that case.
  return std::max(Dtype(1.0), normalizer);
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Forward_cpu(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  // The forward pass computes the softmax prob values.
  softmax_layer_->Forward(softmax_bottom_vec_, softmax_top_vec_);
  const Dtype* prob_data = prob_.cpu_data();
  const Dtype* label = bottom[1]->cpu_data();
  int dim = prob_.count() / outer_num_;
  int count = 0;
  Dtype loss = 0;
  for (int i = 0; i < outer_num_; ++i) {
    for (int j = 0; j < inner_num_; j++) {
      int label_value = static_cast<int>(label[i * inner_num_ + j]);
      /*if (has_ignore_label_ && label_value == ignore_label_) {
        continue;
      }*/
      if (label_value < label_start_ || label_value > label_end_)
          continue;
      label_value -= label_start_;
      DCHECK_GE(label_value, 0);
      DCHECK_LT(label_value, prob_.shape(softmax_axis_));
      loss -= log(std::max(prob_data[i * dim + label_value * inner_num_ + j],
                           Dtype(FLT_MIN)));
      ++count;
    }
  }
  top[0]->mutable_cpu_data()[0] = loss / get_normalizer(normalization_, count);
  if (top.size() == 2) {
    top[1]->ShareData(prob_);
  }
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
  if (propagate_down[1]) {
    LOG(FATAL) << this->type()
               << " Layer cannot backpropagate to label inputs.";
  }
  if (propagate_down[0]) {
    Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
    const Dtype* prob_data = prob_.cpu_data();
    caffe_copy(prob_.count(), prob_data, bottom_diff);
    const Dtype* label = bottom[1]->cpu_data();
    int dim = prob_.count() / outer_num_;
    int count = 0;
    for (int i = 0; i < outer_num_; ++i) {
      for (int j = 0; j < inner_num_; ++j) {
        const int label_value = static_cast<int>(label[i * inner_num_ + j]);
        if (label_value < label_start_ || label_value > label_end_) {
          for (int c = 0; c < bottom[0]->shape(softmax_axis_); ++c) {
            bottom_diff[i * dim + c * inner_num_ + j] = 0;
          }
        } else {
          bottom_diff[i * dim + (label_value - label_start_) * inner_num_ + j] -= 1;
          ++count;
        }
      }
    }
    // Scale gradient
    Dtype loss_weight = top[0]->cpu_diff()[0] /
                        get_normalizer(normalization_, count);
    caffe_scal(prob_.count(), loss_weight, bottom_diff);
  }
}

#ifdef CPU_ONLY
STUB_GPU(SoftmaxWithLossLayer);
#endif

INSTANTIATE_CLASS(SoftmaxWithLossLayer);
REGISTER_LAYER_CLASS(SoftmaxWithLoss);

}  // namespace caffe


#include <algorithm>
#include <cfloat>
#include <vector>

#include "caffe/layers/softmax_loss_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::LayerSetUp(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {

  LayerParameter softmax_param(this->layer_param_);
  softmax_param.set_type("Softmax");
  softmax_layer_ = LayerRegistry<Dtype>::CreateLayer(softmax_param);
  softmax_bottom_vec_.clear();
  softmax_bottom_vec_.push_back(bottom[0]);
  softmax_top_vec_.clear();
  softmax_top_vec_.push_back(&prob_);
  softmax_layer_->SetUp(softmax_bottom_vec_, softmax_top_vec_);

  /*has_ignore_label_ =
    this->layer_param_.loss_param().has_ignore_label();
  if (has_ignore_label_) {
    ignore_label_ = this->layer_param_.loss_param().ignore_label();
  }*/

  if (!this->layer_param_.loss_param().has_normalization() &&
      this->layer_param_.loss_param().has_normalize()) {
    normalization_ = this->layer_param_.loss_param().normalize() ?
                     LossParameter_NormalizationMode_VALID :
                     LossParameter_NormalizationMode_BATCH_SIZE;
  } else {
    normalization_ = this->layer_param_.loss_param().normalization();
  }
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Reshape(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  LossLayer<Dtype>::Reshape(bottom, top);
  softmax_layer_->Reshape(softmax_bottom_vec_, softmax_top_vec_);
  softmax_axis_ =
      bottom[0]->CanonicalAxisIndex(this->layer_param_.softmax_param().axis());
  outer_num_ = bottom[0]->count(0, softmax_axis_);
  inner_num_ = bottom[0]->count(softmax_axis_ + 1);
  CHECK_EQ(outer_num_ * inner_num_, bottom[1]->count())
      << "Number of labels must match number of predictions; "
      << "e.g., if softmax axis == 1 and prediction shape is (N, C, H, W), "
      << "label count (number of labels) must be N*H*W, "
      << "with integer values in {0, 1, ..., C-1}.";
  if (top.size() >= 2) {
    // softmax output
    top[1]->ReshapeLike(*bottom[0]);
  }

  if (this->layer_param_.loss_param().has_label_start())
      label_start_ = this->layer_param_.loss_param().label_start();
  else
      label_start_ = 0;

  if (this->layer_param_.loss_param().has_label_end())
      label_end_ = this->layer_param_.loss_param().label_end();
  else
      label_end_ = prob_.shape(softmax_axis_) - 1;

  static bool not_first_time = 0;
  if (!not_first_time) {
      LOG(INFO) << "valid label value range: [" << label_start_ << ',' << label_end_
          << "], number of classes = " << prob_.shape(softmax_axis_)
          << ", normalization mode = " << normalization_;
      not_first_time = true;
  }

  CHECK_EQ(label_end_ - label_start_ + 1, prob_.shape(softmax_axis_))
      << "valid label count must match the number of predicted classes";
}

template <typename Dtype>
Dtype SoftmaxWithLossLayer<Dtype>::get_normalizer(
    LossParameter_NormalizationMode normalization_mode, int valid_count) {
  Dtype normalizer;
  switch (normalization_mode) {
    case LossParameter_NormalizationMode_FULL:
      normalizer = Dtype(outer_num_ * inner_num_);
      break;
    case LossParameter_NormalizationMode_VALID:
      if (valid_count == -1) {
        normalizer = Dtype(outer_num_ * inner_num_);
      } else {
        normalizer = Dtype(valid_count);
      }
      break;
    case LossParameter_NormalizationMode_BATCH_SIZE:
      normalizer = Dtype(outer_num_);
      break;
    case LossParameter_NormalizationMode_NONE:
      normalizer = Dtype(1);
      break;
    default:
      LOG(FATAL) << "Unknown normalization mode: "
          << LossParameter_NormalizationMode_Name(normalization_mode);
  }
  // Some users will have no labels for some examples in order to 'turn off' a
  // particular loss in a multi-task setup. The max prevents NaNs in that case.
  return std::max(Dtype(1.0), normalizer);
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Forward_cpu(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  // The forward pass computes the softmax prob values.
  softmax_layer_->Forward(softmax_bottom_vec_, softmax_top_vec_);
  const Dtype* prob_data = prob_.cpu_data();
  const Dtype* label = bottom[1]->cpu_data();
  int dim = prob_.count() / outer_num_;
  int count = 0;
  Dtype loss = 0;
  for (int i = 0; i < outer_num_; ++i) {
    for (int j = 0; j < inner_num_; j++) {
      int label_value = static_cast<int>(label[i * inner_num_ + j]);
      /*if (has_ignore_label_ && label_value == ignore_label_) {
        continue;
      }*/
      if (label_value < label_start_ || label_value > label_end_)
          continue;
      label_value -= label_start_;
      DCHECK_GE(label_value, 0);
      DCHECK_LT(label_value, prob_.shape(softmax_axis_));
      loss -= log(std::max(prob_data[i * dim + label_value * inner_num_ + j],
                           Dtype(FLT_MIN)));
      ++count;
    }
  }
  top[0]->mutable_cpu_data()[0] = loss / get_normalizer(normalization_, count);
  if (top.size() == 2) {
    top[1]->ShareData(prob_);
  }
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
  if (propagate_down[1]) {
    LOG(FATAL) << this->type()
               << " Layer cannot backpropagate to label inputs.";
  }
  if (propagate_down[0]) {
    Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
    const Dtype* prob_data = prob_.cpu_data();
    caffe_copy(prob_.count(), prob_data, bottom_diff);
    const Dtype* label = bottom[1]->cpu_data();
    int dim = prob_.count() / outer_num_;
    int count = 0;
    for (int i = 0; i < outer_num_; ++i) {
      for (int j = 0; j < inner_num_; ++j) {
        const int label_value = static_cast<int>(label[i * inner_num_ + j]);
        if (label_value < label_start_ || label_value > label_end_) {
          for (int c = 0; c < bottom[0]->shape(softmax_axis_); ++c) {
            bottom_diff[i * dim + c * inner_num_ + j] = 0;
          }
        } else {
          bottom_diff[i * dim + (label_value - label_start_) * inner_num_ + j] -= 1;
          ++count;
        }
      }
    }
    // Scale gradient
    Dtype loss_weight = top[0]->cpu_diff()[0] /
                        get_normalizer(normalization_, count);
    caffe_scal(prob_.count(), loss_weight, bottom_diff);
  }
}

#ifdef CPU_ONLY
STUB_GPU(SoftmaxWithLossLayer);
#endif

INSTANTIATE_CLASS(SoftmaxWithLossLayer);
REGISTER_LAYER_CLASS(SoftmaxWithLoss);

}  // namespace caffe


if (!not_first_time) {
      LOG(INFO) << "valid label value range: [" << label_start_ << ',' << label_end_
          << "], number of classes = " << prob_.shape(softmax_axis_)
          << ", normalization mode = " << normalization_;
      not_first_time = true;
  }

#include <algorithm>
#include <cfloat>
#include <vector>

#include "caffe/layers/softmax_loss_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::LayerSetUp(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  LossLayer<Dtype>::LayerSetUp(bottom, top);
  LayerParameter softmax_param(this->layer_param_);
  softmax_param.set_type("Softmax");
  softmax_layer_ = LayerRegistry<Dtype>::CreateLayer(softmax_param);
  softmax_bottom_vec_.clear();
  softmax_bottom_vec_.push_back(bottom[0]);
  softmax_top_vec_.clear();
  softmax_top_vec_.push_back(&prob_);
  softmax_layer_->SetUp(softmax_bottom_vec_, softmax_top_vec_);

  /*has_ignore_label_ =
    this->layer_param_.loss_param().has_ignore_label();
  if (has_ignore_label_) {
    ignore_label_ = this->layer_param_.loss_param().ignore_label();
  }*/

  if (!this->layer_param_.loss_param().has_normalization() &&
      this->layer_param_.loss_param().has_normalize()) {
    normalization_ = this->layer_param_.loss_param().normalize() ?
                     LossParameter_NormalizationMode_VALID :
                     LossParameter_NormalizationMode_BATCH_SIZE;
  } else {
    normalization_ = this->layer_param_.loss_param().normalization();
  }
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Reshape(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  LossLayer<Dtype>::Reshape(bottom, top);
  softmax_layer_->Reshape(softmax_bottom_vec_, softmax_top_vec_);
  softmax_axis_ =
      bottom[0]->CanonicalAxisIndex(this->layer_param_.softmax_param().axis());
  outer_num_ = bottom[0]->count(0, softmax_axis_);
  inner_num_ = bottom[0]->count(softmax_axis_ + 1);
  CHECK_EQ(outer_num_ * inner_num_, bottom[1]->count())
      << "Number of labels must match number of predictions; "
      << "e.g., if softmax axis == 1 and prediction shape is (N, C, H, W), "
      << "label count (number of labels) must be N*H*W, "
      << "with integer values in {0, 1, ..., C-1}.";
  if (top.size() >= 2) {
    // softmax output
    top[1]->ReshapeLike(*bottom[0]);
  }

  if (this->layer_param_.loss_param().has_label_start())
      label_start_ = this->layer_param_.loss_param().label_start();
  else
      label_start_ = 0;

  if (this->layer_param_.loss_param().has_label_end())
      label_end_ = this->layer_param_.loss_param().label_end();
  else
      label_end_ = prob_.shape(softmax_axis_) - 1;

  static bool not_first_time = 0;

  CHECK_EQ(label_end_ - label_start_ + 1, prob_.shape(softmax_axis_))
      << "valid label count must match the number of predicted classes";
}

template <typename Dtype>
Dtype SoftmaxWithLossLayer<Dtype>::get_normalizer(
    LossParameter_NormalizationMode normalization_mode, int valid_count) {
  Dtype normalizer;
  switch (normalization_mode) {
    case LossParameter_NormalizationMode_FULL:
      normalizer = Dtype(outer_num_ * inner_num_);
      break;
    case LossParameter_NormalizationMode_VALID:
      if (valid_count == -1) {
        normalizer = Dtype(outer_num_ * inner_num_);
      } else {
        normalizer = Dtype(valid_count);
      }
      break;
    case LossParameter_NormalizationMode_BATCH_SIZE:
      normalizer = Dtype(outer_num_);
      break;
    case LossParameter_NormalizationMode_NONE:
      normalizer = Dtype(1);
      break;
    default:
      LOG(FATAL) << "Unknown normalization mode: "
          << LossParameter_NormalizationMode_Name(normalization_mode);
  }
  // Some users will have no labels for some examples in order to 'turn off' a
  // particular loss in a multi-task setup. The max prevents NaNs in that case.
  return std::max(Dtype(1.0), normalizer);
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Forward_cpu(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  // The forward pass computes the softmax prob values.
  softmax_layer_->Forward(softmax_bottom_vec_, softmax_top_vec_);
  const Dtype* prob_data = prob_.cpu_data();
  const Dtype* label = bottom[1]->cpu_data();
  int dim = prob_.count() / outer_num_;
  int count = 0;
  Dtype loss = 0;
  for (int i = 0; i < outer_num_; ++i) {
    for (int j = 0; j < inner_num_; j++) {
      int label_value = static_cast<int>(label[i * inner_num_ + j]);
      /*if (has_ignore_label_ && label_value == ignore_label_) {
        continue;
      }*/
      if (label_value < label_start_ || label_value > label_end_)
          continue;
      label_value -= label_start_;
      DCHECK_GE(label_value, 0);
      DCHECK_LT(label_value, prob_.shape(softmax_axis_));
      loss -= log(std::max(prob_data[i * dim + label_value * inner_num_ + j],
                           Dtype(FLT_MIN)));
      ++count;
    }
  }
  top[0]->mutable_cpu_data()[0] = loss / get_normalizer(normalization_, count);
  if (top.size() == 2) {
    top[1]->ShareData(prob_);
  }
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
  if (propagate_down[1]) {
    LOG(FATAL) << this->type()
               << " Layer cannot backpropagate to label inputs.";
  }
  if (propagate_down[0]) {
    Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
    const Dtype* prob_data = prob_.cpu_data();
    caffe_copy(prob_.count(), prob_data, bottom_diff);
    const Dtype* label = bottom[1]->cpu_data();
    int dim = prob_.count() / outer_num_;
    int count = 0;
    for (int i = 0; i < outer_num_; ++i) {
      for (int j = 0; j < inner_num_; ++j) {
        const int label_value = static_cast<int>(label[i * inner_num_ + j]);
        if (label_value < label_start_ || label_value > label_end_) {
          for (int c = 0; c < bottom[0]->shape(softmax_axis_); ++c) {
            bottom_diff[i * dim + c * inner_num_ + j] = 0;
          }
        } else {
          bottom_diff[i * dim + (label_value - label_start_) * inner_num_ + j] -= 1;
          ++count;
        }
      }
    }
    // Scale gradient
    Dtype loss_weight = top[0]->cpu_diff()[0] /
                        get_normalizer(normalization_, count);
    caffe_scal(prob_.count(), loss_weight, bottom_diff);
  }
}

#ifdef CPU_ONLY
STUB_GPU(SoftmaxWithLossLayer);
#endif

INSTANTIATE_CLASS(SoftmaxWithLossLayer);
REGISTER_LAYER_CLASS(SoftmaxWithLoss);

}  // namespace caffe


for (int c = 0; c < bottom[0]->shape(softmax_axis_); ++c) {
            bottom_diff[i * dim + c * inner_num_ + j] = 0;
          }

#include <algorithm>
#include <cfloat>
#include <vector>

#include "caffe/layers/softmax_loss_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::LayerSetUp(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  LossLayer<Dtype>::LayerSetUp(bottom, top);
  LayerParameter softmax_param(this->layer_param_);
  softmax_param.set_type("Softmax");
  softmax_layer_ = LayerRegistry<Dtype>::CreateLayer(softmax_param);
  softmax_bottom_vec_.clear();
  softmax_bottom_vec_.push_back(bottom[0]);
  softmax_top_vec_.clear();
  softmax_top_vec_.push_back(&prob_);
  softmax_layer_->SetUp(softmax_bottom_vec_, softmax_top_vec_);

  /*has_ignore_label_ =
    this->layer_param_.loss_param().has_ignore_label();
  if (has_ignore_label_) {
    ignore_label_ = this->layer_param_.loss_param().ignore_label();
  }*/

  if (!this->layer_param_.loss_param().has_normalization() &&
      this->layer_param_.loss_param().has_normalize()) {
    normalization_ = this->layer_param_.loss_param().normalize() ?
                     LossParameter_NormalizationMode_VALID :
                     LossParameter_NormalizationMode_BATCH_SIZE;
  } else {
    normalization_ = this->layer_param_.loss_param().normalization();
  }
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Reshape(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  LossLayer<Dtype>::Reshape(bottom, top);
  softmax_layer_->Reshape(softmax_bottom_vec_, softmax_top_vec_);
  softmax_axis_ =
      bottom[0]->CanonicalAxisIndex(this->layer_param_.softmax_param().axis());
  outer_num_ = bottom[0]->count(0, softmax_axis_);
  inner_num_ = bottom[0]->count(softmax_axis_ + 1);
  CHECK_EQ(outer_num_ * inner_num_, bottom[1]->count())
      << "Number of labels must match number of predictions; "
      << "e.g., if softmax axis == 1 and prediction shape is (N, C, H, W), "
      << "label count (number of labels) must be N*H*W, "
      << "with integer values in {0, 1, ..., C-1}.";
  if (top.size() >= 2) {
    // softmax output
    top[1]->ReshapeLike(*bottom[0]);
  }

  if (this->layer_param_.loss_param().has_label_start())
      label_start_ = this->layer_param_.loss_param().label_start();
  else
      label_start_ = 0;

  if (this->layer_param_.loss_param().has_label_end())
      label_end_ = this->layer_param_.loss_param().label_end();
  else
      label_end_ = prob_.shape(softmax_axis_) - 1;

  static bool not_first_time = 0;
  if (!not_first_time) {
      LOG(INFO) << "valid label value range: [" << label_start_ << ',' << label_end_
          << "], number of classes = " << prob_.shape(softmax_axis_)
          << ", normalization mode = " << normalization_;
      not_first_time = true;
  }

  CHECK_EQ(label_end_ - label_start_ + 1, prob_.shape(softmax_axis_))
      << "valid label count must match the number of predicted classes";
}

template <typename Dtype>
Dtype SoftmaxWithLossLayer<Dtype>::get_normalizer(
    LossParameter_NormalizationMode normalization_mode, int valid_count) {
  Dtype normalizer;
  switch (normalization_mode) {
    case LossParameter_NormalizationMode_FULL:
      normalizer = Dtype(outer_num_ * inner_num_);
      break;
    case LossParameter_NormalizationMode_VALID:
      if (valid_count == -1) {
        normalizer = Dtype(outer_num_ * inner_num_);
      } else {
        normalizer = Dtype(valid_count);
      }
      break;
    case LossParameter_NormalizationMode_BATCH_SIZE:
      normalizer = Dtype(outer_num_);
      break;
    case LossParameter_NormalizationMode_NONE:
      normalizer = Dtype(1);
      break;
    default:
      LOG(FATAL) << "Unknown normalization mode: "
          << LossParameter_NormalizationMode_Name(normalization_mode);
  }
  // Some users will have no labels for some examples in order to 'turn off' a
  // particular loss in a multi-task setup. The max prevents NaNs in that case.
  return std::max(Dtype(1.0), normalizer);
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Forward_cpu(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  // The forward pass computes the softmax prob values.
  softmax_layer_->Forward(softmax_bottom_vec_, softmax_top_vec_);
  const Dtype* prob_data = prob_.cpu_data();
  const Dtype* label = bottom[1]->cpu_data();
  int dim = prob_.count() / outer_num_;
  int count = 0;
  Dtype loss = 0;
  for (int i = 0; i < outer_num_; ++i) {
    for (int j = 0; j < inner_num_; j++) {
      int label_value = static_cast<int>(label[i * inner_num_ + j]);
      /*if (has_ignore_label_ && label_value == ignore_label_) {
        continue;
      }*/
      if (label_value < label_start_ || label_value > label_end_)
          continue;
      label_value -= label_start_;
      DCHECK_GE(label_value, 0);
      DCHECK_LT(label_value, prob_.shape(softmax_axis_));
      loss -= log(std::max(prob_data[i * dim + label_value * inner_num_ + j],
                           Dtype(FLT_MIN)));
      ++count;
    }
  }
  top[0]->mutable_cpu_data()[0] = loss / get_normalizer(normalization_, count);
  if (top.size() == 2) {
    top[1]->ShareData(prob_);
  }
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
  if (propagate_down[1]) {
    LOG(FATAL) << this->type()
               << " Layer cannot backpropagate to label inputs.";
  }
  if (propagate_down[0]) {
    Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
    const Dtype* prob_data = prob_.cpu_data();
    caffe_copy(prob_.count(), prob_data, bottom_diff);
    const Dtype* label = bottom[1]->cpu_data();
    int dim = prob_.count() / outer_num_;
    int count = 0;
    for (int i = 0; i < outer_num_; ++i) {
      for (int j = 0; j < inner_num_; ++j) {
        const int label_value = static_cast<int>(label[i * inner_num_ + j]);
        if (label_value < label_start_ || label_value > label_end_) {

        } else {
          bottom_diff[i * dim + (label_value - label_start_) * inner_num_ + j] -= 1;
          ++count;
        }
      }
    }
    // Scale gradient
    Dtype loss_weight = top[0]->cpu_diff()[0] /
                        get_normalizer(normalization_, count);
    caffe_scal(prob_.count(), loss_weight, bottom_diff);
  }
}

#ifdef CPU_ONLY
STUB_GPU(SoftmaxWithLossLayer);
#endif

INSTANTIATE_CLASS(SoftmaxWithLossLayer);
REGISTER_LAYER_CLASS(SoftmaxWithLoss);

}  // namespace caffe


#include <algorithm>
#include <cfloat>
#include <vector>

#include "caffe/layers/softmax_loss_layer.hpp"
#include "caffe/util/math_functions.hpp"

namespace caffe {

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::LayerSetUp(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  LossLayer<Dtype>::LayerSetUp(bottom, top);
  LayerParameter softmax_param(this->layer_param_);
  softmax_param.set_type("Softmax");
  softmax_layer_ = LayerRegistry<Dtype>::CreateLayer(softmax_param);
  softmax_bottom_vec_.clear();
  softmax_bottom_

vec_.push_back(bottom[0]);
  softmax_top_vec_.clear();
  softmax_top_vec_.push_back(&prob_);
  softmax_layer_->SetUp(softmax_bottom_vec_, softmax_top_vec_);

  /*has_ignore_label_ =
    this->layer_param_.loss_param().has_ignore_label();
  if (has_ignore_label_) {
    ignore_label_ = this->layer_param_.loss_param().ignore_label();
  }*/

  if (!this->layer_param_.loss_param().has_normalization() &&
      this->layer_param_.loss_param().has_normalize()) {
    normalization_ = this->layer_param_.loss_param().normalize() ?
                     LossParameter_NormalizationMode_VALID :
                     LossParameter_NormalizationMode_BATCH_SIZE;
  } else {
    normalization_ = this->layer_param_.loss_param().normalization();
  }
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Reshape(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  LossLayer<Dtype>::Reshape(bottom, top);
  softmax_layer_->Reshape(softmax_bottom_vec_, softmax_top_vec_);
  softmax_axis_ =
      bottom[0]->CanonicalAxisIndex(this->layer_param_.softmax_param().axis());
  outer_num_ = bottom[0]->count(0, softmax_axis_);
  inner_num_ = bottom[0]->count(softmax_axis_ + 1);
  CHECK_EQ(outer_num_ * inner_num_, bottom[1]->count())
      << "Number of labels must match number of predictions; "
      << "e.g., if softmax axis == 1 and prediction shape is (N, C, H, W), "
      << "label count (number of labels) must be N*H*W, "
      << "with integer values in {0, 1, ..., C-1}.";
  if (top.size() >= 2) {
    // softmax output
    top[1]->ReshapeLike(*bottom[0]);
  }

  if (this->layer_param_.loss_param().has_label_start())
      label_start_ = this->layer_param_.loss_param().label_start();
  else
      label_start_ = 0;

  if (this->layer_param_.loss_param().has_label_end())
      label_end_ = this->layer_param_.loss_param().label_end();
  else
      label_end_ = prob_.shape(softmax_axis_) - 1;

  static bool not_first_time = 0;
  if (!not_first_time) {
      LOG(INFO) << "valid label value range: [" << label_start_ << ',' << label_end_
          << "], number of classes = " << prob_.shape(softmax_axis_)
          << ", normalization mode = " << normalization_;
      not_first_time = true;
  }

  CHECK_EQ(label_end_ - label_start_ + 1, prob_.shape(softmax_axis_))
      << "valid label count must match the number of predicted classes";
}

template <typename Dtype>
Dtype SoftmaxWithLossLayer<Dtype>::get_normalizer(
    LossParameter_NormalizationMode normalization_mode, int valid_count) {
  Dtype normalizer;
  switch (normalization_mode) {
    case LossParameter_NormalizationMode_FULL:
      normalizer = Dtype(outer_num_ * inner_num_);
      break;
    case LossParameter_NormalizationMode_VALID:
      if (valid_count == -1) {
        normalizer = Dtype(outer_num_ * inner_num_);
      } else {
        normalizer = Dtype(valid_count);
      }
      break;
    case LossParameter_NormalizationMode_BATCH_SIZE:
      normalizer = Dtype(outer_num_);
      break;
    case LossParameter_NormalizationMode_NONE:
      normalizer = Dtype(1);
      break;
    default:
      LOG(FATAL) << "Unknown normalization mode: "
          << LossParameter_NormalizationMode_Name(normalization_mode);
  }
  // Some users will have no labels for some examples in order to 'turn off' a
  // particular loss in a multi-task setup. The max prevents NaNs in that case.
  return std::max(Dtype(1.0), normalizer);
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Forward_cpu(
    const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
  // The forward pass computes the softmax prob values.
  softmax_layer_->Forward(softmax_bottom_vec_, softmax_top_vec_);
  const Dtype* prob_data = prob_.cpu_data();
  const Dtype* label = bottom[1]->cpu_data();
  int dim = prob_.count() / outer_num_;
  int count = 0;
  Dtype loss = 0;
  for (int i = 0; i < outer_num_; ++i) {
    for (int j = 0; j < inner_num_; j++) {
      int label_value = static_cast<int>(label[i * inner_num_ + j]);
      /*if (has_ignore_label_ && label_value == ignore_label_) {
        continue;
      }*/
      if (label_value < label_start_ || label_value > label_end_)
          continue;
      label_value -= label_start_;
      DCHECK_GE(label_value, 0);
      DCHECK_LT(label_value, prob_.shape(softmax_axis_));
      loss -= log(std::max(prob_data[i * dim + label_value * inner_num_ + j],
                           Dtype(FLT_MIN)));
      ++count;
    }
  }
  top[0]->mutable_cpu_data()[0] = loss / get_normalizer(normalization_, count);
  if (top.size() == 2) {
    top[1]->ShareData(prob_);
  }
}

template <typename Dtype>
void SoftmaxWithLossLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top,
    const vector<bool>& propagate_down, const vector<Blob<Dtype>*>& bottom) {
  if (propagate_down[1]) {
    LOG(FATAL) << this->type()
               << " Layer cannot backpropagate to label inputs.";
  }
  if (propagate_down[0]) {
    Dtype* bottom_diff = bottom[0]->mutable_cpu_diff();
    const Dtype* prob_data = prob_.cpu_data();
    caffe_copy(prob_.count(), prob_data, bottom_diff);
    const Dtype* label = bottom[1]->cpu_data();
    int dim = prob_.count() / outer_num_;
    int count = 0;
    for (int i = 0; i < outer_num_; ++i) {
      for (int j = 0; j < inner_num_; ++j) {
        const int label_value = static_cast<int>(label[i * inner_num_ + j]);
        if (label_value < label_start_ || label_value > label_end_) {
          for (int c = 0; c < bottom[0]->shape(softmax_axis_); ++c) {
            bottom_diff[i * dim + c * inner_num_ + j] = 0;
          }
        } else {
          bottom_diff[i * dim + (label_value - label_start_) * inner_num_ + j] -= 1;
          ++count;
        }
      }
    }
    // Scale gradient
    Dtype loss_weight = top[0]->cpu_diff()[0] /
                        get_normalizer(normalization_, count);
    caffe_scal(prob_.count(), loss_weight, bottom_diff);
  }
}

#ifdef CPU_ONLY
STUB_GPU(SoftmaxWithLossLayer);
#endif

INSTANTIATE_CLASS(SoftmaxWithLossLayer);
REGISTER_LAYER_CLASS(SoftmaxWithLoss);

}  // namespace caffe


/*
 * TimeUtils.cpp
 *
 *  Created on: Nov 20, 2014
 *      Author: Michal.Busta at gmail.com
 *
 */
#include "TimeUtils.h"

#include <opencv2/core/core.hpp>

#ifdef _WIN32
#include <windows.h>
#include <winbase.h>
#endif

namespace cmp
{

{
#ifdef _WIN32
	static LARGE_INTEGER s_frequency;
		static BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency);
		if (s_use_qpc) {
			LARGE_INTEGER now;
			QueryPerformanceCounter(&now);
			return (1000LL * now.QuadPart) / s_frequency.QuadPart;
		}
		else {
			return GetTickCount();
		}
#else
	return cv::getTickCount() / (cv::getTickFrequency()) * 1000;
#endif
}

#ifdef _WIN32
#include <Windows.h>
double get_wall_time(){
    LARGE_INTEGER time,freq;
    if (!QueryPerformanceFrequency(&freq)){
        //  Handle error
        return 0;
    }
    if (!QueryPerformanceCounter(&time)){
        //  Handle error
        return 0;
    }
    return (double)time.QuadPart / freq.QuadPart;
}
double get_cpu_time(){
    FILETIME a,b,c,d;
    if (GetProcessTimes(GetCurrentProcess(),&a,&b,&c,&d) != 0){
        //  Returns total user time.
        //  Can be tweaked to include kernel times as well.
        return
            (double)(d.dwLowDateTime |
            ((unsigned long long)d.dwHighDateTime << 32)) * 0.0001;
    }else{
        //  Handle error
        return 0;
    }
}

//  Posix/Linux
#else
#include <sys/time.h>
double get_wall_time(){
    struct timeval time;
    if (gettimeofday(&time,NULL)){
        //  Handle error
        return 0;
    }
    return (double)time.tv_sec + (double)time.tv_usec * .001;
}
double get_cpu_time(){
    return (double)clock() / CLOCKS_PER_SEC;
}
#endif

} /* namespace cmp */


{
    return (double)clock() / CLOCKS_PER_SEC;
}

/*
 * TimeUtils.cpp
 *
 *  Created on: Nov 20, 2014
 *      Author: Michal.Busta at gmail.com
 *
 */
#include "TimeUtils.h"

#include <opencv2/core/core.hpp>

#ifdef _WIN32
#include <windows.h>
#include <winbase.h>
#endif

namespace cmp
{

long long TimeUtils::MiliseconsNow()
{
#ifdef _WIN32
	static LARGE_INTEGER s_frequency;
		static BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency);
		if (s_use_qpc) {
			LARGE_INTEGER now;
			QueryPerformanceCounter(&now);
			return (1000LL * now.QuadPart) / s_frequency.QuadPart;
		}
		else {
			return GetTickCount();
		}
#else
	return cv::getTickCount() / (cv::getTickFrequency()) * 1000;
#endif
}

#ifdef _WIN32
#include <Windows.h>
double get_wall_time(){
    LARGE_INTEGER time,freq;
    if (!QueryPerformanceFrequency(&freq)){
        //  Handle error
        return 0;
    }
    if (!QueryPerformanceCounter(&time)){
        //  Handle error
        return 0;
    }
    return (double)time.QuadPart / freq.QuadPart;
}
double get_cpu_time(){
    FILETIME a,b,c,d;
    if (GetProcessTimes(GetCurrentProcess(),&a,&b,&c,&d) != 0){
        //  Returns total user time.
        //  Can be tweaked to include kernel times as well.
        return
            (double)(d.dwLowDateTime |
            ((unsigned long long)d.dwHighDateTime << 32)) * 0.0001;
    }else{
        //  Handle error
        return 0;
    }
}

//  Posix/Linux
#else
#include <sys/time.h>
double get_wall_time(){
    struct timeval time;
    if (gettimeofday(&time,NULL)){
        //  Handle error
        return 0;
    }
    return (double)time.tv_sec + (double)time.tv_usec * .001;
}
double get_cpu_time()


/*
 * TimeUtils.cpp
 *
 *  Created on: Nov 20, 2014
 *      Author: Michal.Busta at gmail.com
 *
 */
#include "TimeUtils.h"

#include <opencv2/core/core.hpp>

#ifdef _WIN32
#include <windows.h>
#include <winbase.h>
#endif

namespace cmp
{

long long TimeUtils::MiliseconsNow()
{
#ifdef _WIN32
	static LARGE_INTEGER s_frequency;
		static BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency);
		if (s_use_qpc) {
			LARGE_INTEGER now;
			QueryPerformanceCounter(&now);
			return (1000LL * now.QuadPart) / s_frequency.QuadPart;
		}
		else {
			return GetTickCount();
		}
#else
	return cv::getTickCount() / (cv::getTickFrequency()) * 1000;
#endif
}

#ifdef _WIN32
#include <Windows.h>
double get_wall_time(){
    LARGE_INTEGER time,freq;
    if (!QueryPerformanceFrequency(&freq)){
        //  Handle error
        return 0;
    }
    if (!QueryPerformanceCounter(&time)){
        //  Handle error
        return 0;
    }
    return (double)time.QuadPart / freq.QuadPart;
}
double get_cpu_time(){
    FILETIME a,b,c,d;
    if (GetProcessTimes(GetCurrentProcess(),&a,&b,&c,&d) != 0){
        //  Returns total user time.
        //  Can be tweaked to include kernel times as well.
        return
            (double)(d.dwLowDateTime |
            ((unsigned long long)d.dwHighDateTime << 32)) * 0.0001;
    }else{
        //  Handle error
        return 0;
    }
}

//  Posix/Linux
#else
#include <sys/time.h>
double get_wall_time()

    if (gettimeofday(&time,NULL)){
        //  Handle error
        return 0;
    }
    return (double)time.tv_sec + (double)time.tv_usec * .001;
}
double get_cpu_time(){
    return (double)clock() / CLOCKS_PER_SEC;
}
#endif

} /* namespace cmp */


if (gettimeofday(&time,NULL)){
        //  Handle error
        return 0;
    }

/*
 * TimeUtils.cpp
 *
 *  Created on: Nov 20, 2014
 *      Author: Michal.Busta at gmail.com
 *
 */
#include "TimeUtils.h"

#include <opencv2/core/core.hpp>

#ifdef _WIN32
#include <windows.h>
#include <winbase.h>
#endif

namespace cmp
{

long long TimeUtils::MiliseconsNow()
{
#ifdef _WIN32
	static LARGE_INTEGER s_frequency;
		static BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency);
		if (s_use_qpc) {
			LARGE_INTEGER now;
			QueryPerformanceCounter(&now);
			return (1000LL * now.QuadPart) / s_frequency.QuadPart;
		}
		else {
			return GetTickCount();
		}
#else
	return cv::getTickCount() / (cv::getTickFrequency()) * 1000;
#endif
}

#ifdef _WIN32
#include <Windows.h>
double get_wall_time(){
    LARGE_INTEGER time,freq;
    if (!QueryPerformanceFrequency(&freq)){
        //  Handle error
        return 0;
    }
    if (!QueryPerformanceCounter(&time)){
        //  Handle error
        return 0;
    }
    return (double)time.QuadPart / freq.QuadPart;
}
double get_cpu_time(){
    FILETIME a,b,c,d;
    if (GetProcessTimes(GetCurrentProcess(),&a,&b,&c,&d) != 0){
        //  Returns total user time.
        //  Can be tweaked to include kernel times as well.
        return
            (double)(d.dwLowDateTime |
            ((unsigned long long)d.dwHighDateTime << 32)) * 0.0001;
    }else{
        //  Handle error
        return 0;
    }
}

//  Posix/Linux
#else
#include <sys/time.h>
double get_wall_time(){
    struct timeval time;

    return (double)time.tv_sec + (double)time.tv_usec * .001;
}
double get_cpu_time(){
    return (double)clock() / CLOCKS_PER_SEC;
}
#endif

} /* namespace cmp */


return (double)time.tv_sec + (double)time.tv_usec * .001;
}

/*
 * TimeUtils.cpp
 *
 *  Created on: Nov 20, 2014
 *      Author: Michal.Busta at gmail.com
 *
 */
#include "TimeUtils.h"

#include <opencv2/core/core.hpp>

#ifdef _WIN32
#include <windows.h>
#include <winbase.h>
#endif

namespace cmp
{

long long TimeUtils::MiliseconsNow()
{
#ifdef _WIN32
	static LARGE_INTEGER s_frequency;
		static BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency);
		if (s_use_qpc) {
			LARGE_INTEGER now;
			QueryPerformanceCounter(&now);
			return (1000LL * now.QuadPart) / s_frequency.QuadPart;
		}
		else {
			return GetTickCount();
		}
#else
	return cv::getTickCount() / (cv::getTickFrequency()) * 1000;
#endif
}

#ifdef _WIN32
#include <Windows.h>
double get_wall_time(){
    LARGE_INTEGER time,freq;
    if (!QueryPerformanceFrequency(&freq)){
        //  Handle error
        return 0;
    }
    if (!QueryPerformanceCounter(&time)){
        //  Handle error
        return 0;
    }
    return (double)time.QuadPart / freq.QuadPart;
}
double get_cpu_time(){
    FILETIME a,b,c,d;
    if (GetProcessTimes(GetCurrentProcess(),&a,&b,&c,&d) != 0){
        //  Returns total user time.
        //  Can be tweaked to include kernel times as well.
        return
            (double)(d.dwLowDateTime |
            ((unsigned long long)d.dwHighDateTime << 32)) * 0.0001;
    }else{
        //  Handle error
        return 0;
    }
}

//  Posix/Linux
#else
#include <sys/time.h>
double get_wall_time(){
    struct timeval time;
    if (gettimeofday(&time,NULL)){
        //  Handle error
        return 0;
    }

double get_cpu_time(){
    return (double)clock() / CLOCKS_PER_SEC;
}
#endif

} /* namespace cmp */


/*
 * TimeUtils.cpp
 *
 *  Created on: Nov 20, 2014
 *      Author: Michal.Busta at gmail.com
 *
 */
#include "TimeUtils.h"

#include <opencv2/core/core.hpp>

#ifdef _WIN32
#include <windows.h>
#include <winbase.h>
#endif

namespace cmp
{

long long TimeUtils::MiliseconsNow()
{
#ifdef _WIN32
	static LARGE_INTEGER s_frequency;
		static BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency);
		if (s_use_qpc) {
			LARGE_INTEGER now;
			QueryPerformanceCounter(&now);
			return (1000LL * now.QuadPart) / s_frequency.QuadPart;
		}
		else {
			return GetTickCount();
		}
#else
	return cv::getTickCount() / (cv::getTickFrequency()) * 1000;
#endif
}

#ifdef _WIN32
#include <Windows.h>
double get_wall_time(){
    LARGE_I

    if (!QueryPerformanceFrequency(&freq)){
        //  Handle error
        return 0;
    }
    if (!QueryPerformanceCounter(&time)){
        //  Handle error
        return 0;
    }
    return (double)time.QuadPart / freq.QuadPart;
}
double get_cpu_time(){
    FILETIME a,b,c,d;
    if (GetProcessTimes(GetCurrentProcess(),&a,&b,&c,&d) != 0){
        //  Returns total user time.
        //  Can be tweaked to include kernel times as well.
        return
            (double)(d.dwLowDateTime |
            ((unsigned long long)d.dwHighDateTime << 32)) * 0.0001;
    }else{
        //  Handle error
        return 0;
    }
}

//  Posix/Linux
#else
#include <sys/time.h>
double get_wall_time(){
    struct timeval time;
    if (gettimeofday(&time,NULL)){
        //  Handle error
        return 0;
    }
    return (double)time.tv_sec + (double)time.tv_usec * .001;
}
double get_cpu_time(){
    return (double)clock() / CLOCKS_PER_SEC;
}
#endif

} /* namespace cmp */


if (!QueryPerformanceFrequency(&freq)){
        //  Handle error
        return 0;
    }

/*
 * TimeUtils.cpp
 *
 *  Created on: Nov 20, 2014
 *      Author: Michal.Busta at gmail.com
 *
 */
#include "TimeUtils.h"

#include <opencv2/core/core.hpp>

#ifdef _WIN32
#include <windows.h>
#include <winbase.h>
#endif

namespace cmp
{

long long TimeUtils::MiliseconsNow()
{
#ifdef _WIN32
	static LARGE_INTEGER s_frequency;
		static BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency);
		if (s_use_qpc) {
			LARGE_INTEGER now;
			QueryPerformanceCounter(&now);
			return (1000LL * now.QuadPart) / s_frequency.QuadPart;
		}
		else {
			return GetTickCount();
		}
#else
	return cv::getTickCount() / (cv::getTickFrequency()) * 1000;
#endif
}

#ifdef _WIN32
#include <Windows.h>
double get_wall_time(){
    LARGE_INTEGER time,freq;

    if (!QueryPerformanceCounter(&time)){
        //  Handle error
        return 0;
    }
    return (double)time.QuadPart / freq.QuadPart;
}
double get_cpu_time(){
    FILETIME a,b,c,d;
    if (GetProcessTimes(GetCurrentProcess(),&a,&b,&c,&d) != 0){
        //  Returns total user time.
        //  Can be tweaked to include kernel times as well.
        return
            (double)(d.dwLowDateTime |
            ((unsigned long long)d.dwHighDateTime << 32)) * 0.0001;
    }else{
        //  Handle error
        return 0;
    }
}

//  Posix/Linux
#else
#include <sys/time.h>
double get_wall_time(){
    struct timeval time;
    if (gettimeofday(&time,NULL)){
        //  Handle error
        return 0;
    }
    return (double)time.tv_sec + (double)time.tv_usec * .001;
}
double get_cpu_time(){
    return (double)clock() / CLOCKS_PER_SEC;
}
#endif

} /* namespace cmp */


/*
 * TimeUtils.cpp
 *
 *  Created on: Nov 20, 2014
 *      Author: Michal.Busta at gmail.com
 *
 */
#include "TimeUtils.h"

#include <opencv2/core/core.hpp>

#ifdef _WIN32
#include <windows.h>
#include <winbase.h>
#endif

namespace cmp
{

long long TimeUtils::MiliseconsNow()
{
#ifdef _WIN32
	static LARGE_INTEGER s_frequency;
		static BOOL s_use_qpc = QueryPerformanceFrequency(&s_frequency);
		if (s_use_qpc) {
			LARGE_INTEGER now;
			QueryPerformanceCounter(&now);
			return (1000LL * now.QuadPart) / s_frequency.QuadPart;
		}
		else {
			return GetTickCount();
		}
#else
	return cv::getTickCount() / (cv::getTickFrequency()) * 1000;
#endif
}

#ifdef _WIN32
#include <Windows.h>
double get_wall_time(){
    LARGE_INTEGER time,freq;
    if (!QueryPerformanceFrequency(&freq)){
        //  Handle error
        return 0;
    }
    if (!QueryPerformanceCounter(&t

ime)){
        //  Handle error
        return 0;
    }
    return (double)time.QuadPart / freq.QuadPart;
}
double get_cpu_time(){
    FILETIME a,b,c,d;
    if (GetProcessTimes(GetCurrentProcess(),&a,&b,&c,&d) != 0){
        //  Returns total user time.
        //  Can be tweaked to include kernel times as well.
        return
            (double)(d.dwLowDateTime |
            ((unsigned long long)d.dwHighDateTime << 32)) * 0.0001;
    }else{
        //  Handle error
        return 0;
    }
}

//  Posix/Linux
#else
#include <sys/time.h>
double get_wall_time(){
    struct timeval time;
    if (gettimeofday(&time,NULL)){
        //  Handle error
        return 0;
    }
    return (double)time.tv_sec + (double)time.tv_usec * .001;
}
double get_cpu_time(){
    return (double)clock() / CLOCKS_PER_SEC;
}
#endif

} /* namespace cmp */


QszMonThd(PrimitiveServer* psp, ofstream* qszlog) : fPsp(psp), fQszLog(qszlog)

/*

   */

/***********************************************************************
 *   $Id: primproc.cpp 2147 2013-08-14 20:44:44Z bwilkinson $
 *
 *
 ***********************************************************************/
#include <unistd.h>
#include <string>
#include <iostream>
#ifdef QSIZE_DEBUG
#include <iomanip>
#include <fstream>
#endif
#include <csignal>
#include <sys/time.h>
#ifndef _MSC_VER
#include <sys/resource.h>
#include <tr1/unordered_set>
#else
#include <unordered_set>
#endif
#include <clocale>
#include <iterator>
#include <algorithm>
//#define NDEBUG
#include <cassert>
using namespace std;

#include <boost/thread.hpp>
#include <boost/regex.hpp>
#include <boost/tokenizer.hpp>
using namespace boost;

#include "configcpp.h"
using namespace config;

#include "messageids.h"
using namespace logging;

#include "primproc.h"
#include "primitiveserver.h"
#include "MonitorProcMem.h"
#include "pp_logger.h"
#include "umsocketselector.h"
using namespace primitiveprocessor;

#include "liboamcpp.h"
using namespace oam;

#include "utils_utf8.h"

#include "IDBPolicy.h"
using namespace idbdatafile;

#include "cgroupconfigurator.h"

namespace primitiveprocessor
{

extern uint32_t BPPCount;
extern uint32_t blocksReadAhead;
extern uint32_t defaultBufferSize;
extern uint32_t connectionsPerUM;
extern uint32_t highPriorityThreads;
extern uint32_t medPriorityThreads;
extern uint32_t lowPriorityThreads;
extern int  directIOFlag;
extern int  noVB;

DebugLevel gDebugLevel;
Logger* mlp;
string systemLang;
bool utf8 = false;

bool isDebug( const DebugLevel level )
{
	return level <= gDebugLevel;
}

}

namespace
{

int toInt(const string& val)
{
	if (val.length() == 0)
		return -1;
	return static_cast<int>(Config::fromText(val));
}

void setupSignalHandlers()
{
#ifndef _MSC_VER
	signal(SIGHUP, SIG_IGN);

	struct sigaction ign;

	memset(&ign, 0, sizeof(ign));
	ign.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &ign, 0);

	memset(&ign, 0, sizeof(ign));
	ign.sa_handler = SIG_IGN;
	sigaction(SIGUSR1, &ign, 0);

	memset(&ign, 0, sizeof(ign));
	ign.sa_handler = SIG_IGN;
	sigaction(SIGUSR2, &ign, 0);

	sigset_t sigset;
	sigemptyset(&sigset);
	sigaddset(&sigset, SIGPIPE);
	sigaddset(&sigset, SIGUSR1);
	sigaddset(&sigset, SIGUSR2);
	sigprocmask(SIG_BLOCK, &sigset, 0);

#endif
}

void setupCwd(Config* cf)
{
	string workdir = cf->getConfig("SystemConfig", "WorkingDir");
	if (workdir.length() == 0)
		workdir = ".";
	(void)chdir(workdir.c_str());
	if (access(".", W_OK) != 0)
		(void)chdir("/tmp");
}

int setupResources()
{
#ifndef _MSC_VER
	struct rlimit rlim;

	if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
		return -1;
	}
	rlim.rlim_cur = rlim.rlim_max = 65536;
	if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
		return -2;
	}

	if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
		return -3;
	}

	if (rlim.rlim_cur != 65536) {
		return -4;
	}
#endif
	return 0;
}

#ifdef QSIZE_DEBUG
class QszMonThd
{
public:

{
	}

	~QszMonThd()
	{
	}

	void operator()()
	{
		for (;;)
		{
			uint32_t qd = fPsp->getProcessorThreadPool()->getWaiting();
			if (fQszLog)
			{
				// Get a timestamp for output.
				struct tm tm;
				struct timeval tv;

				gettimeofday(&tv, 0);
				localtime_r(&tv.tv_sec, &tm);

				ostringstream oss;
				oss << setfill('0')
				<< setw(2) << tm.tm_hour << ':'
				<< setw(2) << tm.tm_min << ':'
				<< setw(2) << tm.tm_sec
				<< '.'
				<< setw(4) << tv.tv_usec/100
				;

				*fQszLog << oss.str() << ' ' << qd << endl;
			}
			struct timespec req = { 0, 1000 * 100 }; //100 usec
			nanosleep(&req, 0);
		}
	}
private:
	//defaults okay
	const PrimitiveServer* fPsp;
	ofstream* fQszLog;
};
#endif

#ifndef _MSC_VER
#define DUMP_CACHE_CONTENTS
#endif
#ifdef DUMP_CACHE_CONTENTS
void* waitForSIGUSR1(void* p)
{
#if defined(__LP64__) || defined(_MSC_VER)
	ptrdiff_t tmp = reinterpret_cast<ptrdiff_t>(p);
	int cacheCount = static_cast<int>(tmp);
#else
	int cacheCount = reinterpret_cast<int>(p);
#endif
#ifndef _MSC_VER
	sigset_t oset;
	int rec_sig;
	int32_t rpt_state=0;
	sigfillset(&oset);
	sigdelset(&oset, SIGUSR1);
	sigdelset(&oset, SIGUSR2);
	pthread_sigmask(SIG_SETMASK, &oset, 0);

	sigemptyset(&oset);
	sigaddset(&oset, SIGUSR1);
	sigaddset(&oset, SIGUSR2);
#endif
	for (;;)
	{
		sigwait(&oset, &rec_sig);
		if (rec_sig == SIGUSR1)
		{
#ifdef _MSC_VER
			ofstream out("C:/Calpont/log/trace/pplru.dat");
#else
			ofstream out("/var/log/Calpont/trace/pplru.dat");
#endif
			for (int i = 0; i < cacheCount; i++)
			{
				BRPp[i]->formatLRUList(out);
				out << "###" << endl;
			}
		} else if (rec_sig == SIGUSR2)
		{
			// is reporting currently on?
			rpt_state = BRPp[0]->ReportingFrequency();
			if (rpt_state>0)
				rpt_state=0; // turn reporting off
			else
				rpt_state=1; // fbm will set to the value from config file

			for (int i = 0; i < cacheCount; i++)
				BRPp[i]->setReportingFrequency(rpt_state);
			cout << "@@@" << endl;
		}
	}
	return 0;
}
#endif

}

int main(int argc, char* argv[])
{
	// get and set locale language
	systemLang = funcexp::utf8::idb_setlocale();
	if ( systemLang != "en_US.UTF-8" &&
			systemLang.find("UTF") != string::npos )
		utf8 = true;

	Config* cf = Config::makeConfig();

	setupSignalHandlers();

	setupCwd(cf);

	mlp = new primitiveprocessor::Logger();

	int rc;
	rc = setupResources();
	if (rc) {
		Message::Args args;
		args.add(rc);
	}

	int serverThreads = 1;
	int serverQueueSize = 10;
	int processorWeight = 8*1024;
	int processorQueueSize = 10*1024;
	int BRPBlocksPct = 70;
	uint32_t BRPBlocks = 1887437;
	int BRPThreads = 16;
	int cacheCount = 1;
	int maxBlocksPerRead = 256;  // 1MB
	bool rotatingDestination = false;
	uint32_t deleteBlocks = 128;
	bool PTTrace = false;
	int temp;
	string strTemp;
	int priority = -1;
	const string primitiveServers("PrimitiveServers");
	const string jobListStr("JobList");
	const string dbbc("DBBC");
	const string ExtentMapStr("ExtentMap");
	uint64_t extentRows = 8*1024*1024;
	uint64_t MaxExtentSize = 0;
	double prefetchThreshold;
	uint64_t PMSmallSide = 67108864;
	BPPCount = 16;
	int numCores = -1;
	int configNumCores = -1;
	uint32_t highPriorityPercentage, medPriorityPercentage, lowPriorityPercentage;
	utils::CGroupConfigurator cg;

	gDebugLevel = primitiveprocessor::NONE;

	temp = toInt(cf->getConfig(primitiveServers, "ServerThreads"));
	if (temp > 0)
		serverThreads = temp;

	temp = toInt(cf->getConfig(primitiveServers, "ServerQueueSize"));
	if (temp > 0)
		serverQueueSize = temp;

	temp = toInt(cf->getConfig(primitiveServers, "ProcessorThreshold"));
	if (temp > 0)
		processorWeight = temp;

	temp = toInt(cf->getConfig(primitiveServers, "ProcessorQueueSize"));
	if (temp > 0)
		processorQueueSize = temp;

	temp = toInt(cf->getConfig(primitiveServers, "DebugLevel"));
	if (temp > 0)
		gDebugLevel = (DebugLevel)temp;

	highPriorityPercentage = 0;
	temp = toInt(cf->getConfig(primitiveServers, "HighPriorityPercentage"));
	if (temp >= 0)
		highPriorityPercentage = temp;

	medPriorityPercentage = 0;
	temp = toInt(cf->getConfig(primitiveServers, "MediumPriorityPercentage"));
	if (temp >= 0)
		medPriorityPercentage = temp;

	lowPriorityPercentage = 0;
	temp = toInt(cf->getConfig(primitiveServers, "LowPriorityPercentage"));
	if (temp >= 0)
		lowPriorityPercentage = temp;

	temp = toInt(cf->getConfig(ExtentMapStr, "ExtentRows"));
	if (temp > 0)
		extentRows = temp;

	temp = toInt(cf->getConfig(primitiveServers, "ConnectionsPerPrimProc"));
	if (temp > 0)
		connectionsPerUM = temp;
	else
		connectionsPerUM = 1;

	// set to smallest extent size
	// do not allow to read beyond the end of an extent
	const int MaxReadAheadSz = (extentRows)/BLOCK_SIZE;
	//defaultBufferSize = 512 * 1024; // @bug 2627 - changed default dict buffer from 256K to 512K, allows for cols w/ length of 61.
	defaultBufferSize = 100*1024;  // 1/17/12 - made the dict buffer dynamic, max size for a numeric col is 80k + ovrhd

	// This parm controls whether we rotate through the output sockets
	// when deciding where to send response messages, or whether to simply
	// send the response to the socket of origin.  Should normally be set
	string strVal = cf->getConfig(primitiveServers, "RotatingDestination");
	strVal = "N";
	if ((strVal == "y") || (strVal == "Y")) {
		rotatingDestination = true;

		// Disable destination rotation if UM and PM are running on same
		// server, because we could accidentally end up sending DMLProc
		// responses to ExeMgr and vice versa, if we rotated socket dest.
		temp = toInt(cf->getConfig("Installation", "ServerTypeInstall"));
		if ((temp == oam::INSTALL_COMBINE_DM_UM_PM) ||
				(temp == oam::INSTALL_COMBINE_PM_UM))
			rotatingDestination = false;
	}

	string strBlockPct = cf->getConfig(dbbc, "NumBlocksPct");
	temp = atoi(strBlockPct.c_str());
	if (temp > 0)
		BRPBlocksPct = temp;

#ifdef _MSC_VER
	MEMORYSTATUSEX memStat;
	memStat.dwLength = sizeof(memStat);
	if (GlobalMemoryStatusEx(&memStat) == 0)
		BRPBlocks = 2621 * BRPBlocksPct;
	else
	{
#ifndef _WIN64
		memStat.ullTotalPhys = std::min(memStat.ullTotalVirtual, memStat.ullTotalPhys);
#endif
		//We now have the total phys mem in bytes
		BRPBlocks = memStat.ullTotalPhys / (8 * 1024) / 100 * BRPBlocksPct;
	}
#else
	// _SC_PHYS_PAGES is in 4KB units. Dividing by 200 converts to 8KB and gets ready to work in pct
	// _SC_PHYS_PAGES should always be >> 200 so we shouldn't see a total loss of precision
	BRPBlocks = ((BRPBlocksPct/100.0) * (double) cg.getTotalMemory()) / 8192;
#endif
#if 0
	temp = toInt(cf->getConfig(dbbc, "NumThreads"));
	if (temp > 0)
		BRPThreads = temp;
#endif
	temp = toInt(cf->getConfig(dbbc, "NumCaches"));
	if (temp > 0)
		cacheCount = temp;

	temp = toInt(cf->getConfig(dbbc, "NumDeleteBlocks"));
	if (temp > 0)
		deleteBlocks = temp;

	if ((uint32_t)(.01 * BRPBlocks) < deleteBlocks)
		deleteBlocks = (uint32_t)(.01 * BRPBlocks);

	temp = toInt(cf->getConfig(primitiveServers, "ColScanBufferSizeBlocks"));
	if (temp > (int) MaxReadAheadSz || temp < 1)
		maxBlocksPerRead = MaxReadAheadSz;
	else if (temp > 0)
		maxBlocksPerRead = temp;

	temp = toInt(cf->getConfig(primitiveServers, "ColScanReadAheadBlocks"));
	if (temp > (int) MaxReadAheadSz || temp < 0)
		blocksReadAhead = MaxReadAheadSz;
	else if (temp > 0)
	{
		//make sure we've got an integral factor of extent size
		for (; (MaxExtentSize%temp)!=0; ++temp);
		blocksReadAhead=temp;
	}

	temp = toInt(cf->getConfig(primitiveServers, "PTTrace"));
	if (temp > 0)
		PTTrace = true;

	temp = toInt(cf->getConfig(primitiveServers, "PrefetchThreshold"));
	if (temp < 0 || temp > 100)
		prefetchThreshold = 0;
	else
		prefetchThreshold = temp/100.0;

	int maxPct = 0; //disable by default
	temp = toInt(cf->getConfig(primitiveServers, "MaxPct"));
	if (temp >= 0)
		maxPct = temp;

	// @bug4507, configurable pm aggregation AggregationMemoryCheck
	// We could use this same mechanism for other growing buffers.
	int aggPct = 95;
	temp = toInt(cf->getConfig("SystemConfig", "MemoryCheckPercent"));
	if (temp >= 0)
		aggPct = temp;

	//...Start the thread to monitor our memory usage
	new boost::thread(utils::MonitorProcMem(maxPct, aggPct, 28));

	// config file priority is 40..1 (highest..lowest)
	string sPriority = cf->getConfig(primitiveServers, "Priority");
	if (sPriority.length() > 0)
		temp = toInt(sPriority);
	else
		temp = 21;

	// convert config file value to setpriority(2) value (-20..19, -1 is the default)
	if (temp > 0)
		priority = 20 - temp;
	else if (temp < 0)
		priority = 19;

	if (priority < -20) priority = -20;
#ifdef _MSC_VER
#else
	setpriority(PRIO_PROCESS, 0, priority);
#endif
	//..Instantiate UmSocketSelector singleton.  Disable rotating destination
	//..selection if no UM IP addresses are in the Calpo67108864LLnt.xml file.
	UmSocketSelector* pUmSocketSelector = UmSocketSelector::instance();
	if (rotatingDestination)
	{
		if (pUmSocketSelector->ipAddressCount() < 1)
			rotatingDestination = false;
	}

	//See if we want to override the calculated #cores
	temp = toInt(cf->getConfig(primitiveServers, "NumCores"));
	if (temp > 0)
		configNumCores = temp;

	if (configNumCores <= 0)
	{
		//count the actual #cores

		numCores = cg.getNumCores();
		if (numCores == 0)
			numCores = 8;
	}
	else
		numCores = configNumCores;

	//based on the #cores, calculate some thread parms
	if (numCores > 0)
	{
		BRPThreads = 2 * numCores;
		//there doesn't seem much benefit to having more than this, and sometimes it causes problems.
		//DBBC.NumThreads can override this cap
		BRPThreads = std::min(BRPThreads, 32);
	}

	if (highPriorityPercentage == 0 && medPriorityPercentage == 0 &&
			lowPriorityPercentage == 0) {
		lowPriorityThreads = max(1, (2*numCores)/10);
		medPriorityThreads = max(1, (2*numCores)/3);
		highPriorityThreads = (2 * numCores) - lowPriorityThreads - medPriorityThreads;
	}
	else {
		uint32_t totalThreads = (uint32_t) ((lowPriorityPercentage + medPriorityPercentage +
											 highPriorityPercentage) / 100.0 * (2*numCores));

		if (totalThreads == 0)
			totalThreads = 1;

		lowPriorityThreads = (uint32_t) (lowPriorityPercentage/100.0 * (2*numCores));
		medPriorityThreads = (uint32_t) (medPriorityPercentage/100.0 * (2*numCores));
		highPriorityThreads = totalThreads - lowPriorityThreads - medPriorityThreads;
	}

	BPPCount = highPriorityThreads + medPriorityThreads + lowPriorityThreads;

	// let the user override if they want
	temp = toInt(cf->getConfig(primitiveServers, "BPPCount"));
	if (temp > 0 && temp < (int) BPPCount)
		BPPCount = temp;

	temp = toInt(cf->getConfig(dbbc, "NumThreads"));
	if (temp > 0)
		BRPThreads = temp;

#ifndef _MSC_VER
	// @bug4598, switch for O_DIRECT to support gluster fs.
	strVal = cf->getConfig(primitiveServers, "DirectIO");
	if ((strVal == "n") || (strVal == "N"))
		directIOFlag = 0;
#endif

	IDBPolicy::configIDBPolicy();

	// no versionbuffer if using HDFS for performance reason
	if (IDBPolicy::useHdfs())
		noVB = 1;

	cout << "Starting PrimitiveServer: st = " << serverThreads << ", sq = " << serverQueueSize <<
		 ", pw = " << processorWeight << ", pq = " << processorQueueSize <<
		 ", nb = " << BRPBlocks << ", nt = " << BRPThreads << ", nc = " << cacheCount <<
		 ", ra = " << blocksReadAhead <<  ", db = " << deleteBlocks << ", mb = " << maxBlocksPerRead <<
		 ", rd = " << rotatingDestination << ", tr = " << PTTrace <<
		 ", ss = " << PMSmallSide << ", bp = " << BPPCount << endl;

	PrimitiveServer server(serverThreads, serverQueueSize, processorWeight, processorQueueSize,
						   rotatingDestination, BRPBlocks, BRPThreads, cacheCount, maxBlocksPerRead, blocksReadAhead,
						   deleteBlocks, PTTrace, prefetchThreshold, PMSmallSide);

#ifdef QSIZE_DEBUG
	thread* qszMonThd;
	if (gDebugLevel >= STATS)
	{
#ifdef _MSC_VER
		ofstream* qszLog = new ofstream("C:/Calpont/log/trace/ppqsz.dat");
#else
		ofstream* qszLog = new ofstream("/var/log/Calpont/trace/ppqsz.dat");
#endif
		if (!qszLog->good())
		{
			qszLog->close();
			delete qszLog;
			qszLog = 0;
		}
		qszMonThd = new thread(QszMonThd(&server, qszLog));
	}
#endif

#ifdef DUMP_CACHE_CONTENTS
	{
		//Need to use pthreads API here...
		pthread_t thd1;
		pthread_attr_t attr1;
		pthread_attr_init(&attr1);
		pthread_attr_setdetachstate(&attr1, PTHREAD_CREATE_DETACHED);
		pthread_create(&thd1, &attr1, waitForSIGUSR1, reinterpret_cast<void*>(cacheCount));
	}
#endif

	server.start();

	cerr << "server.start() exited!" << endl;

	return 1;
}


/*

   */

/***********************************************************************
 *   $Id: primproc.cpp 2147 2013-08-14 20:44:44Z bwilkinson $
 *
 *
 ***********************************************************************/
#include <unistd.h>
#include <string>
#include <iostream>
#ifdef QSIZE_DEBUG
#include <iomanip>
#include <fstream>
#endif
#include <csignal>
#include <sys/time.h>
#ifndef _MSC_VER
#include <sys/resource.h>
#include <tr1/unordered_set>
#else
#include <unordered_set>
#endif
#include <clocale>
#include <iterator>
#include <algorithm>
//#define NDEBUG
#include <cassert>
using namespace std;

#include <boost/thread.hpp>
#include <boost/regex.hpp>
#include <boost/tokenizer.hpp>
using namespace boost;

#include "configcpp.h"
using namespace config;

#include "messageids.h"
using namespace logging;

#include "primproc.h"
#include "primitiveserver.h"
#include "MonitorProcMem.h"
#include "pp_logger.h"
#include "umsocketselector.h"
using namespace primitiveprocessor;

#include "liboamcpp.h"
using namespace oam;

#include "utils_utf8.h"

#include "IDBPolicy.h"
using namespace idbdatafile;

#include "cgroupconfigurator.h"

namespace primitiveprocessor
{

extern uint32_t BPPCount;
extern uint32_t blocksReadAhead;
extern uint32_t defaultBufferSize;
extern uint32_t connectionsPerUM;
extern uint32_t highPriorityThreads;
extern uint32_t medPriorityThreads;
extern uint32_t lowPriorityThreads;
extern int  directIOFlag;
extern int  noVB;

DebugLevel gDebugLevel;
Logger* mlp;
string systemLang;
bool utf8 = false;

bool isDebug( const DebugLevel level )

}

namespace
{

int toInt(const string& val)
{
	if (val.length() == 0)
		return -1;
	return static_cast<int>(Config::fromText(val));
}

void setupSignalHandlers()
{
#ifndef _MSC_VER
	signal(SIGHUP, SIG_IGN);

	struct sigaction ign;

	memset(&ign, 0, sizeof(ign));
	ign.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &ign, 0);

	memset(&ign, 0, sizeof(ign));
	ign.sa_handler = SIG_IGN;
	sigaction(SIGUSR1, &ign, 0);

	memset(&ign, 0, sizeof(ign));
	ign.sa_handler = SIG_IGN;
	sigaction(SIGUSR2, &ign, 0);

	sigset_t sigset;
	sigemptyset(&sigset);
	sigaddset(&sigset, SIGPIPE);
	sigaddset(&sigset, SIGUSR1);
	sigaddset(&sigset, SIGUSR2);
	sigprocmask(SIG_BLOCK, &sigset, 0);

#endif
}

void setupCwd(Config* cf)
{
	string workdir = cf->getConfig("SystemConfig", "WorkingDir");
	if (workdir.length() == 0)
		workdir = ".";
	(void)chdir(workdir.c_str());
	if (access(".", W_OK) != 0)
		(void)chdir("/tmp");
}

int setupResources()
{
#ifndef _MSC_VER
	struct rlimit rlim;

	if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
		return -1;
	}
	rlim.rlim_cur = rlim.rlim_max = 65536;
	if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
		return -2;
	}

	if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
		return -3;
	}

	if (rlim.rlim_cur != 65536) {
		return -4;
	}
#endif
	return 0;
}

#ifdef QSIZE_DEBUG
class QszMonThd
{
public:
	QszMonThd(PrimitiveServer* psp, ofstream* qszlog) : fPsp(psp), fQszLog(qszlog)
	{
	}

	~QszMonThd()
	{
	}

	void operator()()
	{
		for (;;)
		{
			uint32_t qd = fPsp->getProcessorThreadPool()->getWaiting();
			if (fQszLog)
			{
				// Get a timestamp for output.
				struct tm tm;
				struct timeval tv;

				gettimeofday(&tv, 0);
				localtime_r(&tv.tv_sec, &tm);

				ostringstream oss;
				oss << setfill('0')
				<< setw(2) << tm.tm_hour << ':'
				<< setw(2) << tm.tm_min << ':'
				<< setw(2) << tm.tm_sec
				<< '.'
				<< setw(4) << tv.tv_usec/100
				;

				*fQszLog << oss.str() << ' ' << qd << endl;
			}
			struct timespec req = { 0, 1000 * 100 }; //100 usec
			nanosleep(&req, 0);
		}
	}
private:
	//defaults okay
	const PrimitiveServer* fPsp;
	ofstream* fQszLog;
};
#endif

#ifndef _MSC_VER
#define DUMP_CACHE_CONTENTS
#endif
#ifdef DUMP_CACHE_CONTENTS
void* waitForSIGUSR1(void* p)
{
#if defined(__LP64__) || defined(_MSC_VER)
	ptrdiff_t tmp = reinterpret_cast<ptrdiff_t>(p);
	int cacheCount = static_cast<int>(tmp);
#else
	int cacheCount = reinterpret_cast<int>(p);
#endif
#ifndef _MSC_VER
	sigset_t oset;
	int rec_sig;
	int32_t rpt_state=0;
	sigfillset(&oset);
	sigdelset(&oset, SIGUSR1);
	sigdelset(&oset, SIGUSR2);
	pthread_sigmask(SIG_SETMASK, &oset, 0);

	sigemptyset(&oset);
	sigaddset(&oset, SIGUSR1);
	sigaddset(&oset, SIGUSR2);
#endif
	for (;;)
	{
		sigwait(&oset, &rec_sig);
		if (rec_sig == SIGUSR1)
		{
#ifdef _MSC_VER
			ofstream out("C:/Calpont/log/trace/pplru.dat");
#else
			ofstream out("/var/log/Calpont/trace/pplru.dat");
#endif
			for (int i = 0; i < cacheCount; i++)
			{
				BRPp[i]->formatLRUList(out);
				out << "###" << endl;
			}
		} else if (rec_sig == SIGUSR2)
		{
			// is reporting currently on?
			rpt_state = BRPp[0]->ReportingFrequency();
			if (rpt_state>0)
				rpt_state=0; // turn reporting off
			else
				rpt_state=1; // fbm will set to the value from config file

			for (int i = 0; i < cacheCount; i++)
				BRPp[i]->setReportingFrequency(rpt_state);
			cout << "@@@" << endl;
		}
	}
	return 0;
}
#endif

}

int main(int argc, char* argv[])
{
	// get and set locale language
	systemLang = funcexp::utf8::idb_setlocale();
	if ( systemLang != "en_US.UTF-8" &&
			systemLang.find("UTF") != string::npos )
		utf8 = true;

	Config* cf = Config::makeConfig();

	setupSignalHandlers();

	setupCwd(cf);

	mlp = new primitiveprocessor::Logger();

	int rc;
	rc = setupResources();
	if (rc) {
		Message::Args args;
		args.add(rc);
	}

	int serverThreads = 1;
	int serverQueueSize = 10;
	int processorWeight = 8*1024;
	int processorQueueSize = 10*1024;
	int BRPBlocksPct = 70;
	uint32_t BRPBlocks = 1887437;
	int BRPThreads = 16;
	int cacheCount = 1;
	int maxBlocksPerRead = 256;  // 1MB
	bool rotatingDestination = false;
	uint32_t deleteBlocks = 128;
	bool PTTrace = false;
	int temp;
	string strTemp;
	int priority = -1;
	const string primitiveServers("PrimitiveServers");
	const string jobListStr("JobList");
	const string dbbc("DBBC");
	const string ExtentMapStr("ExtentMap");
	uint64_t extentRows = 8*1024*1024;
	uint64_t MaxExtentSize = 0;
	double prefetchThreshold;
	uint64_t PMSmallSide = 67108864;
	BPPCount = 16;
	int numCores = -1;
	int configNumCores = -1;
	uint32_t highPriorityPercentage, medPriorityPercentage, lowPriorityPercentage;
	utils::CGroupConfigurator cg;

	gDebugLevel = primitiveprocessor::NONE;

	temp = toInt(cf->getConfig(primitiveServers, "ServerThreads"));
	if (temp > 0)
		serverThreads = temp;

	temp = toInt(cf->getConfig(primitiveServers, "ServerQueueSize"));
	if (temp > 0)
		serverQueueSize = temp;

	temp = toInt(cf->getConfig(primitiveServers, "ProcessorThreshold"));
	if (temp > 0)
		processorWeight = temp;

	temp = toInt(cf->getConfig(primitiveServers, "ProcessorQueueSize"));
	if (temp > 0)
		processorQueueSize = temp;

	temp = toInt(cf->getConfig(primitiveServers, "DebugLevel"));
	if (temp > 0)
		gDebugLevel = (DebugLevel)temp;

	highPriorityPercentage = 0;
	temp = toInt(cf->getConfig(primitiveServers, "HighPriorityPercentage"));
	if (temp >= 0)
		highPriorityPercentage = temp;

	medPriorityPercentage = 0;
	temp = toInt(cf->getConfig(primitiveServers, "MediumPriorityPercentage"));
	if (temp >= 0)
		medPriorityPercentage = temp;

	lowPriorityPercentage = 0;
	temp = toInt(cf->getConfig(primitiveServers, "LowPriorityPercentage"));
	if (temp >= 0)
		lowPriorityPercentage = temp;

	temp = toInt(cf->getConfig(ExtentMapStr, "ExtentRows"));
	if (temp > 0)
		extentRows = temp;

	temp = toInt(cf->getConfig(primitiveServers, "ConnectionsPerPrimProc"));
	if (temp > 0)
		connectionsPerUM = temp;
	else
		connectionsPerUM = 1;

	// set to smallest extent size
	// do not allow to read beyond the end of an extent
	const int MaxReadAheadSz = (extentRows)/BLOCK_SIZE;
	//defaultBufferSize = 512 * 1024; // @bug 2627 - changed default dict buffer from 256K to 512K, allows for cols w/ length of 61.
	defaultBufferSize = 100*1024;  // 1/17/12 - made the dict buffer dynamic, max size for a numeric col is 80k + ovrhd

	// This parm controls whether we rotate through the output sockets
	// when deciding where to send response messages, or whether to simply
	// send the response to the socket of origin.  Should normally be set
	string strVal = cf->getConfig(primitiveServers, "RotatingDestination");
	strVal = "N";
	if ((strVal == "y") || (strVal == "Y")) {
		rotatingDestination = true;

		// Disable destination rotation if UM and PM are running on same
		// server, because we could accidentally end up sending DMLProc
		// responses to ExeMgr and vice versa, if we rotated socket dest.
		temp = toInt(cf->getConfig("Installation", "ServerTypeInstall"));
		if ((temp == oam::INSTALL_COMBINE_DM_UM_PM) ||
				(temp == oam::INSTALL_COMBINE_PM_UM))
			rotatingDestination = false;
	}

	string strBlockPct = cf->getConfig(dbbc, "NumBlocksPct");
	temp = atoi(strBlockPct.c_str());
	if (temp > 0)
		BRPBlocksPct = temp;

#ifdef _MSC_VER
	MEMORYSTATUSEX memStat;
	memStat.dwLength = sizeof(memStat);
	if (GlobalMemoryStatusEx(&memStat) == 0)
		BRPBlocks = 2621 * BRPBlocksPct;
	else
	{
#ifndef _WIN64
		memStat.ullTotalPhys = std::min(memStat.ullTotalVirtual, memStat.ullTotalPhys);
#endif
		//We now have the total phys mem in bytes
		BRPBlocks = memStat.ullTotalPhys / (8 * 1024) / 100 * BRPBlocksPct;
	}
#else
	// _SC_PHYS_PAGES is in 4KB units. Dividing by 200 converts to 8KB and gets ready to work in pct
	// _SC_PHYS_PAGES should always be >> 200 so we shouldn't see a total loss of precision
	BRPBlocks = ((BRPBlocksPct/100.0) * (double) cg.getTotalMemory()) / 8192;
#endif
#if 0
	temp = toInt(cf->getConfig(dbbc, "NumThreads"));
	if (temp > 0)
		BRPThreads = temp;
#endif
	temp = toInt(cf->getConfig(dbbc, "NumCaches"));
	if (temp > 0)
		cacheCount = temp;

	temp = toInt(cf->getConfig(dbbc, "NumDeleteBlocks"));
	if (temp > 0)
		deleteBlocks = temp;

	if ((uint32_t)(.01 * BRPBlocks) < deleteBlocks)
		deleteBlocks = (uint32_t)(.01 * BRPBlocks);

	temp = toInt(cf->getConfig(primitiveServers, "ColScanBufferSizeBlocks"));
	if (temp > (int) MaxReadAheadSz || temp < 1)
		maxBlocksPerRead = MaxReadAheadSz;
	else if (temp > 0)
		maxBlocksPerRead = temp;

	temp = toInt(cf->getConfig(primitiveServers, "ColScanReadAheadBlocks"));
	if (temp > (int) MaxReadAheadSz || temp < 0)
		blocksReadAhead = MaxReadAheadSz;
	else if (temp > 0)
	{
		//make sure we've got an integral factor of extent size
		for (; (MaxExtentSize%temp)!=0; ++temp);
		blocksReadAhead=temp;
	}

	temp = toInt(cf->getConfig(primitiveServers, "PTTrace"));
	if (temp > 0)
		PTTrace = true;

	temp = toInt(cf->getConfig(primitiveServers, "PrefetchThreshold"));
	if (temp < 0 || temp > 100)
		prefetchThreshold = 0;
	else
		prefetchThreshold = temp/100.0;

	int maxPct = 0; //disable by default
	temp = toInt(cf->getConfig(primitiveServers, "MaxPct"));
	if (temp >= 0)
		maxPct = temp;

	// @bug4507, configurable pm aggregation AggregationMemoryCheck
	// We could use this same mechanism for other growing buffers.
	int aggPct = 95;
	temp = toInt(cf->getConfig("SystemConfig", "MemoryCheckPercent"));
	if (temp >= 0)
		aggPct = temp;

	//...Start the thread to monitor our memory usage
	new boost::thread(utils::MonitorProcMem(maxPct, aggPct, 28));

	// config file priority is 40..1 (highest..lowest)
	string sPriority = cf->getConfig(primitiveServers, "Priority");
	if (sPriority.length() > 0)
		temp = toInt(sPriority);
	else
		temp = 21;

	// convert config file value to setpriority(2) value (-20..19, -1 is the default)
	if (temp > 0)
		priority = 20 - temp;
	else if (temp < 0)
		priority = 19;

	if (priority < -20) priority = -20;
#ifdef _MSC_VER
#else
	setpriority(PRIO_PROCESS, 0, priority);
#endif
	//..Instantiate UmSocketSelector singleton.  Disable rotating destination
	//..selection if no UM IP addresses are in the Calpo67108864LLnt.xml file.
	UmSocketSelector* pUmSocketSelector = UmSocketSelector::instance();
	if (rotatingDestination)
	{
		if (pUmSocketSelector->ipAddressCount() < 1)
			rotatingDestination = false;
	}

	//See if we want to override the calculated #cores
	temp = toInt(cf->getConfig(primitiveServers, "NumCores"));
	if (temp > 0)
		configNumCores = temp;

	if (configNumCores <= 0)
	{
		//count the actual #cores

		numCores = cg.getNumCores();
		if (numCores == 0)
			numCores = 8;
	}
	else
		numCores = configNumCores;

	//based on the #cores, calculate some thread parms
	if (numCores > 0)
	{
		BRPThreads = 2 * numCores;
		//there doesn't seem much benefit to having more than this, and sometimes it causes problems.
		//DBBC.NumThreads can override this cap
		BRPThreads = std::min(BRPThreads, 32);
	}

	if (highPriorityPercentage == 0 && medPriorityPercentage == 0 &&
			lowPriorityPercentage == 0) {
		lowPriorityThreads = max(1, (2*numCores)/10);
		medPriorityThreads = max(1, (2*numCores)/3);
		highPriorityThreads = (2 * numCores) - lowPriorityThreads - medPriorityThreads;
	}
	else {
		uint32_t totalThreads = (uint32_t) ((lowPriorityPercentage + medPriorityPercentage +
											 highPriorityPercentage) / 100.0 * (2*numCores));

		if (totalThreads == 0)
			totalThreads = 1;

		lowPriorityThreads = (uint32_t) (lowPriorityPercentage/100.0 * (2*numCores));
		medPriorityThreads = (uint32_t) (medPriorityPercentage/100.0 * (2*numCores));
		highPriorityThreads = totalThreads - lowPriorityThreads - medPriorityThreads;
	}

	BPPCount = highPriorityThreads + medPriorityThreads + lowPriorityThreads;

	// let the user override if they want
	temp = toInt(cf->getConfig(primitiveServers, "BPPCount"));
	if (temp > 0 && temp < (int) BPPCount)
		BPPCount = temp;

	temp = toInt(cf->getConfig(dbbc, "NumThreads"));
	if (temp > 0)
		BRPThreads = temp;

#ifndef _MSC_VER
	// @bug4598, switch for O_DIRECT to support gluster fs.
	strVal = cf->getConfig(primitiveServers, "DirectIO");
	if ((strVal == "n") || (strVal == "N"))
		directIOFlag = 0;
#endif

	IDBPolicy::configIDBPolicy();

	// no versionbuffer if using HDFS for performance reason
	if (IDBPolicy::useHdfs())
		noVB = 1;

	cout << "Starting PrimitiveServer: st = " << serverThreads << ", sq = " << serverQueueSize <<
		 ", pw = " << processorWeight << ", pq = " << processorQueueSize <<
		 ", nb = " << BRPBlocks << ", nt = " << BRPThreads << ", nc = " << cacheCount <<
		 ", ra = " << blocksReadAhead <<  ", db = " << deleteBlocks << ", mb = " << maxBlocksPerRead <<
		 ", rd = " << rotatingDestination << ", tr = " << PTTrace <<
		 ", ss = " << PMSmallSide << ", bp = " << BPPCount << endl;

	PrimitiveServer server(serverThreads, serverQueueSize, processorWeight, processorQueueSize,
						   rotatingDestination, BRPBlocks, BRPThreads, cacheCount, maxBlocksPerRead, blocksReadAhead,
						   deleteBlocks, PTTrace, prefetchThreshold, PMSmallSide);

#ifdef QSIZE_DEBUG
	thread* qszMonThd;
	if (gDebugLevel >= STATS)
	{
#ifdef _MSC_VER
		ofstream* qszLog = new ofstream("C:/Calpont/log/trace/ppqsz.dat");
#else
		ofstream* qszLog = new ofstream("/var/log/Calpont/trace/ppqsz.dat");
#endif
		if (!qszLog->good())
		{
			qszLog->close();
			delete qszLog;
			qszLog = 0;
		}
		qszMonThd = new thread(QszMonThd(&server, qszLog));
	}
#endif

#ifdef DUMP_CACHE_CONTENTS
	{
		//Need to use pthreads API here...
		pthread_t thd1;
		pthread_attr_t attr1;
		pthread_attr_init(&attr1);
		pthread_attr_setdetachstate(&attr1, PTHREAD_CREATE_DETACHED);
		pthread_create(&thd1, &attr1, waitForSIGUSR1, reinterpret_cast<void*>(cacheCount));
	}
#endif

	server.start();

	cerr << "server.start() exited!" << endl;

	return 1;
}