<commit_before>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id: */

// Macro to generate ad hoc GMS alignment matrices in the agreed format:
// TClonesArray saved in the Root file with a key "GMSarray"
// containing TGeoHMatrix with TObject::fUniqueID equal to the geometry
// module Id
//
// By I. Hrivnacova, IPN Orsay

#if !defined(__CINT__) || defined(__MAKECINT__)
#include "AliMpConstants.h"
#endif

MUONGenerateTestGMS()
{
  TFile f("data/GMS.root", "RECREATE");
  TClonesArray* array = new TClonesArray("TGeoHMatrix",100);

  for (Int_t i=0; i<AliMpConstants::NofGeomModules(); i++) {
    TGeoHMatrix* m = new((*array)[i]) TGeoHMatrix();
    m->SetUniqueID(i);
    /// rotate by small angle
    m->RotateX(i*0.01);
  }

  gFile->WriteObject(array,"GMSarray");
  f.Close();
}
<commit_msg>Replaced use of global gFile with the local file.<commit_after>/**************************************************************************
 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

/* $Id: */

// Macro to generate ad hoc GMS alignment matrices in the agreed format:
// TClonesArray saved in the Root file with a key "GMSarray"
// containing TGeoHMatrix with TObject::fUniqueID equal to the geometry
// module Id
//
// By I. Hrivnacova, IPN Orsay

#if !defined(__CINT__) || defined(__MAKECINT__)
#include "AliMpConstants.h"
#endif

MUONGenerateTestGMS()
{
  TFile f("data/GMS.root", "RECREATE");
  TClonesArray* array = new TClonesArray("TGeoHMatrix",100);

  for (Int_t i=0; i<AliMpConstants::NofGeomModules(); i++) {
    TGeoHMatrix* m = new((*array)[i]) TGeoHMatrix();
    m->SetUniqueID(i);
    /// rotate by small angle
    m->RotateX(i*0.01);
  }

  f.WriteObject(array,"GMSarray");
  f.Close();
}
<|endoftext|>


<commit_before>/* Copyright 2019 The TensorFlow Authors. 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 "tensorflow/lite/tools/benchmark/benchmark_performance_options.h"

#include <algorithm>
#include <iomanip>
#include <memory>
#include <sstream>
#include <utility>

#include "tensorflow/core/util/stats_calculator.h"
#include "tensorflow/lite/c/c_api_internal.h"
#if defined(__ANDROID__)
#include "tensorflow/lite/delegates/gpu/delegate.h"
#include "tensorflow/lite/nnapi/nnapi_util.h"
#endif
#include "tensorflow/lite/profiling/time.h"
#include "tensorflow/lite/tools/benchmark/benchmark_params.h"
#include "tensorflow/lite/tools/benchmark/benchmark_utils.h"
#include "tensorflow/lite/tools/benchmark/logging.h"
#include "tensorflow/lite/tools/command_line_flags.h"

namespace tflite {
namespace benchmark {

void MultiRunStatsRecorder::OnBenchmarkStart(const BenchmarkParams& params) {
  current_run_name_.clear();

#if defined(__ANDROID__)
  if (params.Get<bool>("use_nnapi")) {
    current_run_name_ = "nnapi";
    const std::string accelerator =
        params.Get<std::string>("nnapi_accelerator_name");
    if (!accelerator.empty()) {
      current_run_name_ = "nnapi(" + accelerator + ")";
    }
    return;
  }
#endif

  if (params.Get<bool>("use_gpu")) {
#if defined(__ANDROID__)
    const bool allow_precision_loss =
        params.Get<bool>("gpu_precision_loss_allowed");
    const std::string precision_tag = allow_precision_loss ? "fp16" : "fp32";
    current_run_name_ = "gpu(" + precision_tag + ")";

    const auto default_opts = TfLiteGpuDelegateOptionsV2Default();
    if (default_opts.is_precision_loss_allowed == allow_precision_loss) {
      current_run_name_ += "-default";
    }
#else
    current_run_name_ = "gpu-default";
#endif
    return;
  }

  // Handle cases run on CPU
  // Note: could use std::to_string to convert an integer to string but it
  // requires C++11.
  std::stringstream sstm;
  sstm << "cpu w/ " << params.Get<int32_t>("num_threads") << " threads";
  current_run_name_ = sstm.str();
}

void MultiRunStatsRecorder::OnBenchmarkEnd(const BenchmarkResults& results) {
  each_run_stats_.emplace_back(std::make_pair(current_run_name_, results));
}

void MultiRunStatsRecorder::OutputStats() {
  // Make a 80-character-long header.
  TFLITE_LOG(INFO) << "\n==============Summary of All Runs w/ Different "
                      "Performance Options==============";
  std::sort(each_run_stats_.begin(), each_run_stats_.end(),
            EachRunStatsEntryComparator());

  for (const auto& run_stats : each_run_stats_) {
    std::stringstream stream;
    // Output the name of this run first.
    stream << std::setw(26) << run_stats.first << ": ";
    run_stats.second.inference_time_us().OutputToStream(&stream);
    TFLITE_LOG(INFO) << stream.str();
  }
}

BenchmarkPerformanceOptions::BenchmarkPerformanceOptions(
    BenchmarkModel* single_option_run)
    : BenchmarkPerformanceOptions(DefaultParams(), single_option_run,
                                  DefaultRunStatsRecorder()) {}

BenchmarkPerformanceOptions::BenchmarkPerformanceOptions(
    BenchmarkParams params, BenchmarkModel* single_option_run,
    std::unique_ptr<MultiRunStatsRecorder> all_run_stats)
    : params_(std::move(params)),
      single_option_run_(single_option_run),
      single_option_run_params_(single_option_run->mutable_params()),
      all_run_stats_(std::move(all_run_stats)) {
  single_option_run_->AddListener(all_run_stats_.get());
}

BenchmarkParams BenchmarkPerformanceOptions::DefaultParams() {
  BenchmarkParams params;
  params.AddParam("perf_options_list",
                  BenchmarkParam::Create<std::string>("all"));
  params.AddParam("option_benchmark_run_delay",
                  BenchmarkParam::Create<float>(-1.0f));
  params.AddParam("random_shuffle_benchmark_runs",
                  BenchmarkParam::Create<bool>(true));
  return params;
}

std::unique_ptr<MultiRunStatsRecorder>
BenchmarkPerformanceOptions::DefaultRunStatsRecorder() {
  return std::unique_ptr<MultiRunStatsRecorder>(new MultiRunStatsRecorder());
}

std::vector<Flag> BenchmarkPerformanceOptions::GetFlags() {
  return {
      CreateFlag<std::string>(
          "perf_options_list", &params_,
          "A comma-separated list of TFLite performance options to benchmark. "
          "By default, all performance options are benchmarked."),
      CreateFlag<float>("option_benchmark_run_delay", &params_,
                        "The delay between two consecutive runs of "
                        "benchmarking performance options in seconds."),
      CreateFlag<bool>(
          "random_shuffle_benchmark_runs", &params_,
          "Whether to perform all benchmark runs, each of which has different "
          "performance options, in a random order. It is enabled by default."),
  };
}

bool BenchmarkPerformanceOptions::ParseFlags(int* argc, char** argv) {
  auto flag_list = GetFlags();
  const bool parse_result =
      Flags::Parse(argc, const_cast<const char**>(argv), flag_list);
  if (!parse_result) {
    std::string usage = Flags::Usage(argv[0], flag_list);
    TFLITE_LOG(ERROR) << usage;
    return false;
  }

  // Parse the value of --perf_options_list to find performance options to be
  // benchmarked.
  return ParsePerfOptions();
}

bool BenchmarkPerformanceOptions::ParsePerfOptions() {
  const auto& perf_options_list = params_.Get<std::string>("perf_options_list");
  if (!util::SplitAndParse(perf_options_list, ',', &perf_options_)) {
    TFLITE_LOG(ERROR) << "Cannot parse --perf_options_list: '"
                      << perf_options_list
                      << "'. Please double-check its value.";
    perf_options_.clear();
    return false;
  }

  const auto valid_options = GetValidPerfOptions();
  bool is_valid = true;
  for (const auto& option : perf_options_) {
    if (std::find(valid_options.begin(), valid_options.end(), option) ==
        valid_options.end()) {
      is_valid = false;
      break;
    }
  }
  if (!is_valid) {
    std::string valid_options_str;
    for (int i = 0; i < valid_options.size() - 1; ++i) {
      valid_options_str += (valid_options[i] + ", ");
    }
    valid_options_str += valid_options.back();
    TFLITE_LOG(ERROR)
        << "There are invalid perf options in --perf_options_list: '"
        << perf_options_list << "'. Valid perf options are: ["
        << valid_options_str << "]";
    perf_options_.clear();
    return false;
  }
  return true;
}

std::vector<std::string> BenchmarkPerformanceOptions::GetValidPerfOptions()
    const {
  return {"all", "cpu", "gpu", "nnapi"};
}

bool BenchmarkPerformanceOptions::HasOption(const std::string& option) const {
  return std::find(perf_options_.begin(), perf_options_.end(), option) !=
         perf_options_.end();
}

void BenchmarkPerformanceOptions::ResetPerformanceOptions() {
  single_option_run_params_->Set<int32_t>("num_threads", 1);
  single_option_run_params_->Set<bool>("use_gpu", false);
#if defined(__ANDROID__)
  single_option_run_params_->Set<bool>("gpu_precision_loss_allowed", true);
  single_option_run_params_->Set<bool>("use_nnapi", false);
  single_option_run_params_->Set<std::string>("nnapi_accelerator_name", "");
#endif
}

void BenchmarkPerformanceOptions::CreatePerformanceOptions() {
  TFLITE_LOG(INFO) << "The list of TFLite runtime options to be benchmarked: ["
                   << params_.Get<std::string>("perf_options_list") << "]";

  const bool benchmark_all = HasOption("all");

  if (benchmark_all || HasOption("cpu")) {
    const std::vector<int> num_threads = {1, 2, 4};
    for (const int count : num_threads) {
      BenchmarkParams params;
      params.AddParam("num_threads", BenchmarkParam::Create<int32_t>(count));
      all_run_params_.emplace_back(std::move(params));
    }
  }

  if (benchmark_all || HasOption("gpu")) {
#if defined(__ANDROID__)
    const std::vector<bool> allow_precision_loss = {true, false};
    for (const auto precision_loss : allow_precision_loss) {
      BenchmarkParams params;
      params.AddParam("use_gpu", BenchmarkParam::Create<bool>(true));
      params.AddParam("gpu_precision_loss_allowed",
                      BenchmarkParam::Create<bool>(precision_loss));
      all_run_params_.emplace_back(std::move(params));
    }
#else
    BenchmarkParams params;
    params.AddParam("use_gpu", BenchmarkParam::Create<bool>(true));
    all_run_params_.emplace_back(std::move(params));
#endif
  }

#if defined(__ANDROID__)
  if (benchmark_all || HasOption("nnapi")) {
    std::string nnapi_accelerators = nnapi::GetStringDeviceNamesList();
    if (!nnapi_accelerators.empty()) {
      std::vector<std::string> device_names;
      util::SplitAndParse(nnapi_accelerators, ',', &device_names);
      for (const auto name : device_names) {
        BenchmarkParams params;
        params.AddParam("use_nnapi", BenchmarkParam::Create<bool>(true));
        params.AddParam("nnapi_accelerator_name",
                        BenchmarkParam::Create<std::string>(name));
        all_run_params_.emplace_back(std::move(params));
      }
    } else {
      BenchmarkParams params;
      params.AddParam("use_nnapi", BenchmarkParam::Create<bool>(true));
      all_run_params_.emplace_back(std::move(params));
    }
  }
#endif
}

void BenchmarkPerformanceOptions::Run(int argc, char** argv) {
  // We first parse flags for single-option runs to get information like
  // parameters of the input model etc.
  if (single_option_run_->ParseFlags(&argc, argv) != kTfLiteOk) return;

  // Now, we parse flags that are specified for this particular binary.
  if (!ParseFlags(&argc, argv)) return;

  // Now, the remaining are unrecognized flags and we simply print them out.
  for (int i = 1; i < argc; ++i) {
    TFLITE_LOG(WARN) << "WARNING: unrecognized commandline flag: " << argv[i];
  }

  CreatePerformanceOptions();

  if (params_.Get<bool>("random_shuffle_benchmark_runs")) {
    std::random_shuffle(all_run_params_.begin(), all_run_params_.end());
  }

  // Now perform all runs, each with different performance-affecting parameters.
  for (const auto& run_params : all_run_params_) {
    // Reset all performance-related options before any runs.
    ResetPerformanceOptions();
    single_option_run_params_->Set(run_params);
    util::SleepForSeconds(params_.Get<float>("option_benchmark_run_delay"));
    single_option_run_->Run();
  }

  all_run_stats_->OutputStats();
}
}  // namespace benchmark
}  // namespace tflite
<commit_msg>Also benchmark nnapi execution when no explicit accelerator name is specified as the nnapi execution path is different.<commit_after>/* Copyright 2019 The TensorFlow Authors. 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 "tensorflow/lite/tools/benchmark/benchmark_performance_options.h"

#include <algorithm>
#include <iomanip>
#include <memory>
#include <sstream>
#include <utility>

#include "tensorflow/core/util/stats_calculator.h"
#include "tensorflow/lite/c/c_api_internal.h"
#if defined(__ANDROID__)
#include "tensorflow/lite/delegates/gpu/delegate.h"
#include "tensorflow/lite/nnapi/nnapi_util.h"
#endif
#include "tensorflow/lite/profiling/time.h"
#include "tensorflow/lite/tools/benchmark/benchmark_params.h"
#include "tensorflow/lite/tools/benchmark/benchmark_utils.h"
#include "tensorflow/lite/tools/benchmark/logging.h"
#include "tensorflow/lite/tools/command_line_flags.h"

namespace tflite {
namespace benchmark {

void MultiRunStatsRecorder::OnBenchmarkStart(const BenchmarkParams& params) {
  current_run_name_.clear();

#if defined(__ANDROID__)
  if (params.Get<bool>("use_nnapi")) {
    const std::string accelerator =
        params.Get<std::string>("nnapi_accelerator_name");
    current_run_name_ = accelerator.empty() ? "nnapi(w/o accel name)"
                                            : "nnapi(" + accelerator + ")";
    return;
  }
#endif

  if (params.Get<bool>("use_gpu")) {
#if defined(__ANDROID__)
    const bool allow_precision_loss =
        params.Get<bool>("gpu_precision_loss_allowed");
    const std::string precision_tag = allow_precision_loss ? "fp16" : "fp32";
    current_run_name_ = "gpu(" + precision_tag + ")";

    const auto default_opts = TfLiteGpuDelegateOptionsV2Default();
    if (default_opts.is_precision_loss_allowed == allow_precision_loss) {
      current_run_name_ += "-default";
    }
#else
    current_run_name_ = "gpu-default";
#endif
    return;
  }

  // Handle cases run on CPU
  // Note: could use std::to_string to convert an integer to string but it
  // requires C++11.
  std::stringstream sstm;
  sstm << "cpu w/ " << params.Get<int32_t>("num_threads") << " threads";
  current_run_name_ = sstm.str();
}

void MultiRunStatsRecorder::OnBenchmarkEnd(const BenchmarkResults& results) {
  each_run_stats_.emplace_back(std::make_pair(current_run_name_, results));
}

void MultiRunStatsRecorder::OutputStats() {
  // Make a 80-character-long header.
  TFLITE_LOG(INFO) << "\n==============Summary of All Runs w/ Different "
                      "Performance Options==============";
  std::sort(each_run_stats_.begin(), each_run_stats_.end(),
            EachRunStatsEntryComparator());

  for (const auto& run_stats : each_run_stats_) {
    std::stringstream stream;
    // Output the name of this run first.
    stream << std::setw(26) << run_stats.first << ": ";
    run_stats.second.inference_time_us().OutputToStream(&stream);
    TFLITE_LOG(INFO) << stream.str();
  }
}

BenchmarkPerformanceOptions::BenchmarkPerformanceOptions(
    BenchmarkModel* single_option_run)
    : BenchmarkPerformanceOptions(DefaultParams(), single_option_run,
                                  DefaultRunStatsRecorder()) {}

BenchmarkPerformanceOptions::BenchmarkPerformanceOptions(
    BenchmarkParams params, BenchmarkModel* single_option_run,
    std::unique_ptr<MultiRunStatsRecorder> all_run_stats)
    : params_(std::move(params)),
      single_option_run_(single_option_run),
      single_option_run_params_(single_option_run->mutable_params()),
      all_run_stats_(std::move(all_run_stats)) {
  single_option_run_->AddListener(all_run_stats_.get());
}

BenchmarkParams BenchmarkPerformanceOptions::DefaultParams() {
  BenchmarkParams params;
  params.AddParam("perf_options_list",
                  BenchmarkParam::Create<std::string>("all"));
  params.AddParam("option_benchmark_run_delay",
                  BenchmarkParam::Create<float>(-1.0f));
  params.AddParam("random_shuffle_benchmark_runs",
                  BenchmarkParam::Create<bool>(true));
  return params;
}

std::unique_ptr<MultiRunStatsRecorder>
BenchmarkPerformanceOptions::DefaultRunStatsRecorder() {
  return std::unique_ptr<MultiRunStatsRecorder>(new MultiRunStatsRecorder());
}

std::vector<Flag> BenchmarkPerformanceOptions::GetFlags() {
  return {
      CreateFlag<std::string>(
          "perf_options_list", &params_,
          "A comma-separated list of TFLite performance options to benchmark. "
          "By default, all performance options are benchmarked."),
      CreateFlag<float>("option_benchmark_run_delay", &params_,
                        "The delay between two consecutive runs of "
                        "benchmarking performance options in seconds."),
      CreateFlag<bool>(
          "random_shuffle_benchmark_runs", &params_,
          "Whether to perform all benchmark runs, each of which has different "
          "performance options, in a random order. It is enabled by default."),
  };
}

bool BenchmarkPerformanceOptions::ParseFlags(int* argc, char** argv) {
  auto flag_list = GetFlags();
  const bool parse_result =
      Flags::Parse(argc, const_cast<const char**>(argv), flag_list);
  if (!parse_result) {
    std::string usage = Flags::Usage(argv[0], flag_list);
    TFLITE_LOG(ERROR) << usage;
    return false;
  }

  // Parse the value of --perf_options_list to find performance options to be
  // benchmarked.
  return ParsePerfOptions();
}

bool BenchmarkPerformanceOptions::ParsePerfOptions() {
  const auto& perf_options_list = params_.Get<std::string>("perf_options_list");
  if (!util::SplitAndParse(perf_options_list, ',', &perf_options_)) {
    TFLITE_LOG(ERROR) << "Cannot parse --perf_options_list: '"
                      << perf_options_list
                      << "'. Please double-check its value.";
    perf_options_.clear();
    return false;
  }

  const auto valid_options = GetValidPerfOptions();
  bool is_valid = true;
  for (const auto& option : perf_options_) {
    if (std::find(valid_options.begin(), valid_options.end(), option) ==
        valid_options.end()) {
      is_valid = false;
      break;
    }
  }
  if (!is_valid) {
    std::string valid_options_str;
    for (int i = 0; i < valid_options.size() - 1; ++i) {
      valid_options_str += (valid_options[i] + ", ");
    }
    valid_options_str += valid_options.back();
    TFLITE_LOG(ERROR)
        << "There are invalid perf options in --perf_options_list: '"
        << perf_options_list << "'. Valid perf options are: ["
        << valid_options_str << "]";
    perf_options_.clear();
    return false;
  }
  return true;
}

std::vector<std::string> BenchmarkPerformanceOptions::GetValidPerfOptions()
    const {
  return {"all", "cpu", "gpu", "nnapi"};
}

bool BenchmarkPerformanceOptions::HasOption(const std::string& option) const {
  return std::find(perf_options_.begin(), perf_options_.end(), option) !=
         perf_options_.end();
}

void BenchmarkPerformanceOptions::ResetPerformanceOptions() {
  single_option_run_params_->Set<int32_t>("num_threads", 1);
  single_option_run_params_->Set<bool>("use_gpu", false);
#if defined(__ANDROID__)
  single_option_run_params_->Set<bool>("gpu_precision_loss_allowed", true);
  single_option_run_params_->Set<bool>("use_nnapi", false);
  single_option_run_params_->Set<std::string>("nnapi_accelerator_name", "");
#endif
}

void BenchmarkPerformanceOptions::CreatePerformanceOptions() {
  TFLITE_LOG(INFO) << "The list of TFLite runtime options to be benchmarked: ["
                   << params_.Get<std::string>("perf_options_list") << "]";

  const bool benchmark_all = HasOption("all");

  if (benchmark_all || HasOption("cpu")) {
    const std::vector<int> num_threads = {1, 2, 4};
    for (const int count : num_threads) {
      BenchmarkParams params;
      params.AddParam("num_threads", BenchmarkParam::Create<int32_t>(count));
      all_run_params_.emplace_back(std::move(params));
    }
  }

  if (benchmark_all || HasOption("gpu")) {
#if defined(__ANDROID__)
    const std::vector<bool> allow_precision_loss = {true, false};
    for (const auto precision_loss : allow_precision_loss) {
      BenchmarkParams params;
      params.AddParam("use_gpu", BenchmarkParam::Create<bool>(true));
      params.AddParam("gpu_precision_loss_allowed",
                      BenchmarkParam::Create<bool>(precision_loss));
      all_run_params_.emplace_back(std::move(params));
    }
#else
    BenchmarkParams params;
    params.AddParam("use_gpu", BenchmarkParam::Create<bool>(true));
    all_run_params_.emplace_back(std::move(params));
#endif
  }

#if defined(__ANDROID__)
  if (benchmark_all || HasOption("nnapi")) {
    std::string nnapi_accelerators = nnapi::GetStringDeviceNamesList();
    if (!nnapi_accelerators.empty()) {
      std::vector<std::string> device_names;
      util::SplitAndParse(nnapi_accelerators, ',', &device_names);
      for (const auto name : device_names) {
        BenchmarkParams params;
        params.AddParam("use_nnapi", BenchmarkParam::Create<bool>(true));
        params.AddParam("nnapi_accelerator_name",
                        BenchmarkParam::Create<std::string>(name));
        all_run_params_.emplace_back(std::move(params));
      }
    }
    // Explicitly test the case when there's no "nnapi_accelerator_name"
    // parameter as the nnpai execution is different from the case when
    // an accelerator name is explicitly specified.
    BenchmarkParams params;
    params.AddParam("use_nnapi", BenchmarkParam::Create<bool>(true));
    all_run_params_.emplace_back(std::move(params));
  }
#endif
}

void BenchmarkPerformanceOptions::Run(int argc, char** argv) {
  // We first parse flags for single-option runs to get information like
  // parameters of the input model etc.
  if (single_option_run_->ParseFlags(&argc, argv) != kTfLiteOk) return;

  // Now, we parse flags that are specified for this particular binary.
  if (!ParseFlags(&argc, argv)) return;

  // Now, the remaining are unrecognized flags and we simply print them out.
  for (int i = 1; i < argc; ++i) {
    TFLITE_LOG(WARN) << "WARNING: unrecognized commandline flag: " << argv[i];
  }

  CreatePerformanceOptions();

  if (params_.Get<bool>("random_shuffle_benchmark_runs")) {
    std::random_shuffle(all_run_params_.begin(), all_run_params_.end());
  }

  // Now perform all runs, each with different performance-affecting parameters.
  for (const auto& run_params : all_run_params_) {
    // Reset all performance-related options before any runs.
    ResetPerformanceOptions();
    single_option_run_params_->Set(run_params);
    util::SleepForSeconds(params_.Get<float>("option_benchmark_run_delay"));
    single_option_run_->Run();
  }

  all_run_stats_->OutputStats();
}
}  // namespace benchmark
}  // namespace tflite
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "murmur3_partitioner.hh"
#include "utils/murmur_hash.hh"
#include "sstables/key.hh"
#include "utils/class_registrator.hh"
#include <boost/lexical_cast.hpp>

namespace dht {

inline
int64_t
murmur3_partitioner::normalize(int64_t in) {
    return in == std::numeric_limits<int64_t>::lowest()
            ? std::numeric_limits<int64_t>::max()
            : in;
}

token
murmur3_partitioner::get_token(bytes_view key) {
    if (key.empty()) {
        return minimum_token();
    }
    std::array<uint64_t, 2> hash;
    utils::murmur_hash::hash3_x64_128(key, 0, hash);
    return get_token(hash[0]);
}

token
murmur3_partitioner::get_token(uint64_t value) const {
    // We don't normalize() the value, since token includes an is-before-everything
    // indicator.
    // FIXME: will this require a repair when importing a database?
    auto t = net::hton(normalize(value));
    bytes b(bytes::initialized_later(), 8);
    std::copy_n(reinterpret_cast<int8_t*>(&t), 8, b.begin());
    return token{token::kind::key, std::move(b)};
}

token
murmur3_partitioner::get_token(const sstables::key_view& key) {
    return get_token(bytes_view(key));
}

token
murmur3_partitioner::get_token(const schema& s, partition_key_view key) {
    std::array<uint64_t, 2> hash;
    auto&& legacy = key.legacy_form(s);
    utils::murmur_hash::hash3_x64_128(legacy.begin(), legacy.size(), 0, hash);
    return get_token(hash[0]);
}

token murmur3_partitioner::get_random_token() {
    auto rand = dht::get_random_number<uint64_t>();
    return get_token(rand);
}

inline int64_t long_token(const token& t) {
    if (t.is_minimum()) {
        return std::numeric_limits<long>::min();
    }

    if (t._data.size() != sizeof(int64_t)) {
        throw runtime_exception(sprint("Invalid token. Should have size %ld, has size %ld\n", sizeof(int64_t), t._data.size()));
    }

    auto ptr = t._data.begin();
    auto lp = unaligned_cast<const int64_t *>(ptr);
    return net::ntoh(*lp);
}

sstring murmur3_partitioner::to_sstring(const token& t) const {
    return ::to_sstring(long_token(t));
}

dht::token murmur3_partitioner::from_sstring(const sstring& t) const {
    auto lp = boost::lexical_cast<long>(t);
    if (lp == std::numeric_limits<long>::min()) {
        return minimum_token();
    } else {
        return get_token(uint64_t(lp));
    }
}

dht::token murmur3_partitioner::from_bytes(bytes_view bytes) const {
    if (bytes.size() != sizeof(int64_t)) {
        throw runtime_exception(sprint("Invalid token. Should have size %ld, has size %ld\n", sizeof(int64_t), bytes.size()));
    }

    int64_t v;
    std::copy_n(bytes.begin(), sizeof(v), reinterpret_cast<int8_t *>(&v));
    auto tok = net::ntoh(v);
    if (tok == std::numeric_limits<int64_t>::min()) {
        return minimum_token();
    } else {
        return dht::token(dht::token::kind::key, bytes);
    }
}

int murmur3_partitioner::tri_compare(const token& t1, const token& t2) const {
    auto l1 = long_token(t1);
    auto l2 = long_token(t2);

    if (l1 == l2) {
        return 0;
    } else {
        return l1 < l2 ? -1 : 1;
    }
}

// Assuming that x>=y, return the positive difference x-y.
// The return type is an unsigned type, as the difference may overflow
// a signed type (e.g., consider very positive x and very negative y).
template <typename T>
static std::make_unsigned_t<T> positive_subtract(T x, T y) {
        return std::make_unsigned_t<T>(x) - std::make_unsigned_t<T>(y);
}

token murmur3_partitioner::midpoint(const token& t1, const token& t2) const {
    auto l1 = long_token(t1);
    auto l2 = long_token(t2);
    int64_t mid;
    if (l1 <= l2) {
        // To find the midpoint, we cannot use the trivial formula (l1+l2)/2
        // because the addition can overflow the integer. To avoid this
        // overflow, we first notice that the above formula is equivalent to
        // l1 + (l2-l1)/2. Now, "l2-l1" can still overflow a signed integer
        // (e.g., think of a very positive l2 and very negative l1), but
        // because l1 <= l2 in this branch, we note that l2-l1 is positive
        // and fits an *unsigned* int's range. So,
        mid = l1 + positive_subtract(l2, l1)/2;
    } else {
        // When l2 < l1, we need to switch l1 and and l2 in the above
        // formula, because now l1 - l2 is positive.
        // Additionally, we consider this case is a "wrap around", so we need
        // to behave as if l2 + 2^64 was meant instead of l2, i.e., add 2^63
        // to the average.
        mid = l2 + positive_subtract(l1, l2)/2 + 0x8000'0000'0000'0000;
    }
    return get_token(mid);
}

static float ratio_helper(int64_t a, int64_t b) {

    uint64_t val = (a > b)? static_cast<uint64_t>(a) - static_cast<uint64_t>(b) : (static_cast<uint64_t>(a) - static_cast<uint64_t>(b) - 1);
    return val/(float)std::numeric_limits<uint64_t>::max();
}

std::map<token, float>
murmur3_partitioner::describe_ownership(const std::vector<token>& sorted_tokens) {
    std::map<token, float> ownerships;
    auto i = sorted_tokens.begin();

    // 0-case
    if (i == sorted_tokens.end()) {
        throw runtime_exception("No nodes present in the cluster. Has this node finished starting up?");
    }
    // 1-case
    if (sorted_tokens.size() == 1) {
        ownerships[sorted_tokens[0]] = 1.0;
    // n-case
    } else {
        const token& start = sorted_tokens[0];

        int64_t ti = long_token(start);  // The first token and its value
        int64_t start_long = ti;
        int64_t tim1 = ti; // The last token and its value (after loop)
        for (i++; i != sorted_tokens.end(); i++) {
            ti = long_token(*i); // The next token and its value
            ownerships[*i]= ratio_helper(ti, tim1);  // save (T(i) -> %age)
            tim1 = ti;
        }

        // The start token's range extends backward to the last token, which is why both were saved above.
        ownerships[start] = ratio_helper(start_long, ti);
    }

    return ownerships;
}

data_type
murmur3_partitioner::get_token_validator() {
    return long_type;
}

unsigned
murmur3_partitioner::shard_of(const token& t) const {
    switch (t._kind) {
        case token::kind::before_all_keys:
            return 0;
        case token::kind::after_all_keys:
            return _shard_count - 1;
        case token::kind::key:
            int64_t l = long_token(t);
            // treat l as a fraction between 0 and 1 and use 128-bit arithmetic to
            // divide that range evenly among shards:
            uint64_t adjusted = uint64_t(l) + uint64_t(std::numeric_limits<int64_t>::min());
            return (__int128(adjusted) * _shard_count) >> 64;
    }
    assert(0);
}

token
murmur3_partitioner::token_for_next_shard(const token& t) const {
    switch (t._kind) {
        case token::kind::before_all_keys:
            return token_for_next_shard(get_token(std::numeric_limits<int64_t>::min() + 1));
        case token::kind::after_all_keys:
            return maximum_token();
        case token::kind::key:
            if (long_token(t) == std::numeric_limits<int64_t>::min()) {
                return token_for_next_shard(get_token(std::numeric_limits<int64_t>::min() + 1));
            }
            using uint128 = unsigned __int128;
            auto s = shard_of(t) + 1;
            if (s == _shard_count) {
                return maximum_token();
            }
            uint64_t e = (uint128(s) << 64) / _shard_count;
            while (((uint128(e) * _shard_count) >> 64) != s) {
                // division will round down, so correct for it
                ++e;
            }
            return get_token(e + uint64_t(std::numeric_limits<int64_t>::min()));
    }
    assert(0);
}

using registry = class_registrator<i_partitioner, murmur3_partitioner>;
static registry registrator("org.apache.cassandra.dht.Murmur3Partitioner");
static registry registrator_short_name("Murmur3Partitioner");

}

<commit_msg>murmur3_partitioner: Convert maximum_token to sstring<commit_after>/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "murmur3_partitioner.hh"
#include "utils/murmur_hash.hh"
#include "sstables/key.hh"
#include "utils/class_registrator.hh"
#include <boost/lexical_cast.hpp>

namespace dht {

inline
int64_t
murmur3_partitioner::normalize(int64_t in) {
    return in == std::numeric_limits<int64_t>::lowest()
            ? std::numeric_limits<int64_t>::max()
            : in;
}

token
murmur3_partitioner::get_token(bytes_view key) {
    if (key.empty()) {
        return minimum_token();
    }
    std::array<uint64_t, 2> hash;
    utils::murmur_hash::hash3_x64_128(key, 0, hash);
    return get_token(hash[0]);
}

token
murmur3_partitioner::get_token(uint64_t value) const {
    // We don't normalize() the value, since token includes an is-before-everything
    // indicator.
    // FIXME: will this require a repair when importing a database?
    auto t = net::hton(normalize(value));
    bytes b(bytes::initialized_later(), 8);
    std::copy_n(reinterpret_cast<int8_t*>(&t), 8, b.begin());
    return token{token::kind::key, std::move(b)};
}

token
murmur3_partitioner::get_token(const sstables::key_view& key) {
    return get_token(bytes_view(key));
}

token
murmur3_partitioner::get_token(const schema& s, partition_key_view key) {
    std::array<uint64_t, 2> hash;
    auto&& legacy = key.legacy_form(s);
    utils::murmur_hash::hash3_x64_128(legacy.begin(), legacy.size(), 0, hash);
    return get_token(hash[0]);
}

token murmur3_partitioner::get_random_token() {
    auto rand = dht::get_random_number<uint64_t>();
    return get_token(rand);
}

inline int64_t long_token(const token& t) {
    if (t.is_minimum() || t.is_maximum()) {
        return std::numeric_limits<long>::min();
    }

    if (t._data.size() != sizeof(int64_t)) {
        throw runtime_exception(sprint("Invalid token. Should have size %ld, has size %ld\n", sizeof(int64_t), t._data.size()));
    }

    auto ptr = t._data.begin();
    auto lp = unaligned_cast<const int64_t *>(ptr);
    return net::ntoh(*lp);
}

sstring murmur3_partitioner::to_sstring(const token& t) const {
    return ::to_sstring(long_token(t));
}

dht::token murmur3_partitioner::from_sstring(const sstring& t) const {
    auto lp = boost::lexical_cast<long>(t);
    if (lp == std::numeric_limits<long>::min()) {
        return minimum_token();
    } else {
        return get_token(uint64_t(lp));
    }
}

dht::token murmur3_partitioner::from_bytes(bytes_view bytes) const {
    if (bytes.size() != sizeof(int64_t)) {
        throw runtime_exception(sprint("Invalid token. Should have size %ld, has size %ld\n", sizeof(int64_t), bytes.size()));
    }

    int64_t v;
    std::copy_n(bytes.begin(), sizeof(v), reinterpret_cast<int8_t *>(&v));
    auto tok = net::ntoh(v);
    if (tok == std::numeric_limits<int64_t>::min()) {
        return minimum_token();
    } else {
        return dht::token(dht::token::kind::key, bytes);
    }
}

int murmur3_partitioner::tri_compare(const token& t1, const token& t2) const {
    auto l1 = long_token(t1);
    auto l2 = long_token(t2);

    if (l1 == l2) {
        return 0;
    } else {
        return l1 < l2 ? -1 : 1;
    }
}

// Assuming that x>=y, return the positive difference x-y.
// The return type is an unsigned type, as the difference may overflow
// a signed type (e.g., consider very positive x and very negative y).
template <typename T>
static std::make_unsigned_t<T> positive_subtract(T x, T y) {
        return std::make_unsigned_t<T>(x) - std::make_unsigned_t<T>(y);
}

token murmur3_partitioner::midpoint(const token& t1, const token& t2) const {
    auto l1 = long_token(t1);
    auto l2 = long_token(t2);
    int64_t mid;
    if (l1 <= l2) {
        // To find the midpoint, we cannot use the trivial formula (l1+l2)/2
        // because the addition can overflow the integer. To avoid this
        // overflow, we first notice that the above formula is equivalent to
        // l1 + (l2-l1)/2. Now, "l2-l1" can still overflow a signed integer
        // (e.g., think of a very positive l2 and very negative l1), but
        // because l1 <= l2 in this branch, we note that l2-l1 is positive
        // and fits an *unsigned* int's range. So,
        mid = l1 + positive_subtract(l2, l1)/2;
    } else {
        // When l2 < l1, we need to switch l1 and and l2 in the above
        // formula, because now l1 - l2 is positive.
        // Additionally, we consider this case is a "wrap around", so we need
        // to behave as if l2 + 2^64 was meant instead of l2, i.e., add 2^63
        // to the average.
        mid = l2 + positive_subtract(l1, l2)/2 + 0x8000'0000'0000'0000;
    }
    return get_token(mid);
}

static float ratio_helper(int64_t a, int64_t b) {

    uint64_t val = (a > b)? static_cast<uint64_t>(a) - static_cast<uint64_t>(b) : (static_cast<uint64_t>(a) - static_cast<uint64_t>(b) - 1);
    return val/(float)std::numeric_limits<uint64_t>::max();
}

std::map<token, float>
murmur3_partitioner::describe_ownership(const std::vector<token>& sorted_tokens) {
    std::map<token, float> ownerships;
    auto i = sorted_tokens.begin();

    // 0-case
    if (i == sorted_tokens.end()) {
        throw runtime_exception("No nodes present in the cluster. Has this node finished starting up?");
    }
    // 1-case
    if (sorted_tokens.size() == 1) {
        ownerships[sorted_tokens[0]] = 1.0;
    // n-case
    } else {
        const token& start = sorted_tokens[0];

        int64_t ti = long_token(start);  // The first token and its value
        int64_t start_long = ti;
        int64_t tim1 = ti; // The last token and its value (after loop)
        for (i++; i != sorted_tokens.end(); i++) {
            ti = long_token(*i); // The next token and its value
            ownerships[*i]= ratio_helper(ti, tim1);  // save (T(i) -> %age)
            tim1 = ti;
        }

        // The start token's range extends backward to the last token, which is why both were saved above.
        ownerships[start] = ratio_helper(start_long, ti);
    }

    return ownerships;
}

data_type
murmur3_partitioner::get_token_validator() {
    return long_type;
}

unsigned
murmur3_partitioner::shard_of(const token& t) const {
    switch (t._kind) {
        case token::kind::before_all_keys:
            return 0;
        case token::kind::after_all_keys:
            return _shard_count - 1;
        case token::kind::key:
            int64_t l = long_token(t);
            // treat l as a fraction between 0 and 1 and use 128-bit arithmetic to
            // divide that range evenly among shards:
            uint64_t adjusted = uint64_t(l) + uint64_t(std::numeric_limits<int64_t>::min());
            return (__int128(adjusted) * _shard_count) >> 64;
    }
    assert(0);
}

token
murmur3_partitioner::token_for_next_shard(const token& t) const {
    switch (t._kind) {
        case token::kind::before_all_keys:
            return token_for_next_shard(get_token(std::numeric_limits<int64_t>::min() + 1));
        case token::kind::after_all_keys:
            return maximum_token();
        case token::kind::key:
            if (long_token(t) == std::numeric_limits<int64_t>::min()) {
                return token_for_next_shard(get_token(std::numeric_limits<int64_t>::min() + 1));
            }
            using uint128 = unsigned __int128;
            auto s = shard_of(t) + 1;
            if (s == _shard_count) {
                return maximum_token();
            }
            uint64_t e = (uint128(s) << 64) / _shard_count;
            while (((uint128(e) * _shard_count) >> 64) != s) {
                // division will round down, so correct for it
                ++e;
            }
            return get_token(e + uint64_t(std::numeric_limits<int64_t>::min()));
    }
    assert(0);
}

using registry = class_registrator<i_partitioner, murmur3_partitioner>;
static registry registrator("org.apache.cassandra.dht.Murmur3Partitioner");
static registry registrator_short_name("Murmur3Partitioner");

}

<|endoftext|>


<commit_before>/* Copyright 2020 The TensorFlow Authors. 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 "tensorflow/compiler/xla/service/dot_as_convolution_util.h"

#include "absl/types/optional.h"
#include "tensorflow/compiler/xla/service/hlo_instruction.h"
#include "tensorflow/compiler/xla/service/hlo_opcode.h"
#include "tensorflow/compiler/xla/service/shape_inference.h"
#include "tensorflow/compiler/xla/status_macros.h"

namespace xla {
namespace dot_as_convolution_util {

bool ConvSpatialDimensionIsParallel(const WindowDimension& wd, int64 lhs_size) {
  // A parallel batch dimension in DotGeneral is represented as a
  // spatial dimension with window size B (batch dimension size),
  // stride B - 1, and base dilation B.
  if (lhs_size == wd.size() && lhs_size == wd.base_dilation() &&
      ((std::max<int64>(1, lhs_size - 1) == wd.stride() &&
        wd.window_dilation() == 1) ||
       (std::max<int64>(1, lhs_size - 1) == wd.window_dilation() &&
        wd.stride() == 1)) &&
      wd.padding_high() == 0 && wd.padding_low() == 0 &&
      !wd.window_reversal()) {
    return true;
  }

  // Aternative representation of a batch dimension.
  if (wd.size() == lhs_size && wd.padding_high() == lhs_size - 1 &&
      wd.padding_low() == lhs_size - 1 && wd.window_reversal() &&
      wd.window_dilation() == 1 && wd.stride() == lhs_size &&
      wd.base_dilation() == lhs_size - 1) {
    return true;
  }

  return false;
}

/* static */ DotConvolutionDimsInfo ParseConvolutionDimsInfo(
    const HloInstruction* conv) {
  CHECK_EQ(conv->opcode(), HloOpcode::kConvolution);
  const auto& conv_dims = conv->convolution_dimension_numbers();
  DotConvolutionDimsInfo dims;
  dims.lhs_non_contracting_dims.push_back(
      {conv_dims.input_batch_dimension(), -1,
       conv_dims.output_batch_dimension(), -1});
  dims.rhs_non_contracting_dims.push_back(
      {-1, conv_dims.kernel_output_feature_dimension(),
       conv_dims.output_feature_dimension(), -1});
  dims.contracting_dims.push_back({conv_dims.input_feature_dimension(),
                                   conv_dims.kernel_input_feature_dimension(),
                                   -1, -1});

  for (int64 i = 0; i < conv_dims.input_spatial_dimensions_size(); ++i) {
    int64 lhs = conv_dims.input_spatial_dimensions(i);
    int64 lhs_size = conv->operand(0)->shape().dimensions(lhs);
    int64 rhs = conv_dims.kernel_spatial_dimensions(i);
    int64 rhs_size = conv->operand(1)->shape().dimensions(rhs);
    int64 output = conv_dims.output_spatial_dimensions(i);
    const auto& wd = conv->window().dimensions(i);
    if (ConvSpatialDimensionIsParallel(wd, lhs_size)) {
      dims.batch_dims.push_back({lhs, rhs, output, i});
    } else if (lhs_size == wd.size() && wd.base_dilation() == 1 &&
               wd.window_dilation() == 1 && wd.padding_high() == 0 &&
               wd.padding_low() == 0 && !wd.window_reversal()) {
      // A contracting dimension be represented as a spatial dimension with
      // window size C (contracting dimension size). Stride can be any size
      // since there is only one window.
      dims.contracting_dims.push_back({lhs, rhs, output, i});
    } else if (wd.stride() == 1 && wd.window_dilation() == 1 &&
               wd.base_dilation() == 1) {
      if (rhs_size == 1 && wd.size() == 1 && wd.padding_high() == 0 &&
          wd.padding_low() == 0 && !wd.window_reversal()) {
        // A LHS non-contracting dimension can be represented as a spatial
        // dimension with window size 1.
        dims.lhs_non_contracting_dims.push_back({lhs, rhs, output, i});
      } else if (lhs_size == 1 && wd.size() == rhs_size &&
                 wd.padding_high() == rhs_size - 1 &&
                 wd.padding_low() == rhs_size - 1 && wd.window_reversal()) {
        // A RHS non-contracting dimension can be represented as a spatial
        // dimension with window size N (non-contracting dimension size), low
        // padding N - 1,  high padding N - 1 and window reversal.
        dims.rhs_non_contracting_dims.push_back({lhs, rhs, output, i});
      } else {
        dims.conv_spatial_dims.push_back({lhs, rhs, output, i});
      }
    } else {
      dims.conv_spatial_dims.push_back({lhs, rhs, output, i});
    }
  }

  return dims;
}

StatusOr<std::unique_ptr<HloInstruction>>
CreateShardedConvForDotGeneralConvolution(
    const HloInstruction& conv, const DotConvolutionDimsInfo& dot_dnums,
    HloInstruction* sharded_lhs_hlo, HloInstruction* sharded_rhs_hlo) {
  CHECK_EQ(conv.opcode(), HloOpcode::kConvolution);
  const auto& conv_dnums = conv.convolution_dimension_numbers();
  auto window = conv.window();
  for (const auto& dim : dot_dnums.batch_dims) {
    auto wd = window.mutable_dimensions(dim.spatial_dim);
    wd->set_size(sharded_lhs_hlo->shape().dimensions(
        conv_dnums.input_spatial_dimensions(dim.spatial_dim)));
    wd->set_stride(std::max<int64>(1, wd->size() - 1));
    wd->set_base_dilation(wd->size());
  }
  for (const auto& dim : dot_dnums.contracting_dims) {
    if (dim.spatial_dim < 0) {
      continue;
    }
    auto wd = window.mutable_dimensions(dim.spatial_dim);
    wd->set_size(sharded_lhs_hlo->shape().dimensions(
        conv_dnums.input_spatial_dimensions(dim.spatial_dim)));
  }
  for (const auto& dim : dot_dnums.rhs_non_contracting_dims) {
    if (dim.spatial_dim < 0) {
      continue;
    }
    auto wd = window.mutable_dimensions(dim.spatial_dim);
    wd->set_size(sharded_rhs_hlo->shape().dimensions(
        conv_dnums.kernel_spatial_dimensions(dim.spatial_dim)));
    wd->set_padding_high(wd->size() - 1);
    wd->set_padding_low(wd->size() - 1);
  }
  TF_ASSIGN_OR_RETURN(Shape sharded_conv_shape,
                      ShapeInference::InferConvolveShape(
                          sharded_lhs_hlo->shape(), sharded_rhs_hlo->shape(),
                          /*feature_group_count=*/1,
                          /*batch_group_count=*/1, window, conv_dnums));
  *sharded_conv_shape.mutable_layout() = conv.shape().layout();
  return HloInstruction::CreateConvolve(
      sharded_conv_shape, sharded_lhs_hlo, sharded_rhs_hlo,
      /*feature_group_count=*/1,
      /*batch_group_count=*/1, window, conv_dnums, conv.precision_config());
}

DotConvolutionDimsInfo ParseDotGeneralFromDot(const HloInstruction* dot) {
  const auto& dot_dim_numbs = dot->dot_dimension_numbers();
  dot_as_convolution_util::DotConvolutionDimsInfo dnums;
  for (int64 i = 0; i < dot_dim_numbs.lhs_batch_dimensions().size(); ++i) {
    dnums.batch_dims.emplace_back();
    dnums.batch_dims.back().lhs = dot_dim_numbs.lhs_batch_dimensions(i);
    dnums.batch_dims.back().rhs = dot_dim_numbs.rhs_batch_dimensions(i);
    dnums.batch_dims.back().output = i;
    dnums.batch_dims.back().spatial_dim = -1;
  }
  for (int64 i = 0; i < dot_dim_numbs.lhs_contracting_dimensions().size();
       ++i) {
    dnums.contracting_dims.emplace_back();
    dnums.contracting_dims.back().lhs =
        dot_dim_numbs.lhs_contracting_dimensions(i);
    dnums.contracting_dims.back().rhs =
        dot_dim_numbs.rhs_contracting_dimensions(i);
    dnums.contracting_dims.back().output = -1;
    dnums.contracting_dims.back().spatial_dim = -1;
  }
  for (int64 i = 0; i < dot->operand(0)->shape().rank(); ++i) {
    if (!absl::c_linear_search(dot_dim_numbs.lhs_batch_dimensions(), i) &&
        !absl::c_linear_search(dot_dim_numbs.lhs_contracting_dimensions(), i)) {
      dnums.lhs_non_contracting_dims.emplace_back();
      dnums.lhs_non_contracting_dims.back().lhs = i;
      dnums.lhs_non_contracting_dims.back().rhs = -1;
      dnums.lhs_non_contracting_dims.back().output =
          dot_dim_numbs.lhs_batch_dimensions_size() +
          dnums.lhs_non_contracting_dims.size() - 1;
      dnums.lhs_non_contracting_dims.back().spatial_dim = -1;
    }
  }
  for (int64 i = 0; i < dot->operand(1)->shape().rank(); ++i) {
    if (!absl::c_linear_search(dot_dim_numbs.rhs_batch_dimensions(), i) &&
        !absl::c_linear_search(dot_dim_numbs.rhs_contracting_dimensions(), i)) {
      dnums.rhs_non_contracting_dims.emplace_back();
      dnums.rhs_non_contracting_dims.back().lhs = -1;
      dnums.rhs_non_contracting_dims.back().rhs = i;
      dnums.rhs_non_contracting_dims.back().output =
          dot_dim_numbs.lhs_batch_dimensions_size() +
          dnums.lhs_non_contracting_dims.size() +
          dnums.rhs_non_contracting_dims.size() - 1;
      dnums.rhs_non_contracting_dims.back().spatial_dim = -1;
    }
  }
  return dnums;
}

}  // namespace dot_as_convolution_util
}  // namespace xla
<commit_msg>[XLA:SPMD] Fix SPMD issue with replicated depthwise convolution.<commit_after>/* Copyright 2020 The TensorFlow Authors. 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 "tensorflow/compiler/xla/service/dot_as_convolution_util.h"

#include "absl/types/optional.h"
#include "tensorflow/compiler/xla/service/hlo_instruction.h"
#include "tensorflow/compiler/xla/service/hlo_opcode.h"
#include "tensorflow/compiler/xla/service/shape_inference.h"
#include "tensorflow/compiler/xla/status_macros.h"

namespace xla {
namespace dot_as_convolution_util {

bool ConvSpatialDimensionIsParallel(const WindowDimension& wd, int64 lhs_size) {
  // A parallel batch dimension in DotGeneral is represented as a
  // spatial dimension with window size B (batch dimension size),
  // stride B - 1, and base dilation B.
  if (lhs_size == wd.size() && lhs_size == wd.base_dilation() &&
      ((std::max<int64>(1, lhs_size - 1) == wd.stride() &&
        wd.window_dilation() == 1) ||
       (std::max<int64>(1, lhs_size - 1) == wd.window_dilation() &&
        wd.stride() == 1)) &&
      wd.padding_high() == 0 && wd.padding_low() == 0 &&
      !wd.window_reversal()) {
    return true;
  }

  // Aternative representation of a batch dimension.
  if (wd.size() == lhs_size && wd.padding_high() == lhs_size - 1 &&
      wd.padding_low() == lhs_size - 1 && wd.window_reversal() &&
      wd.window_dilation() == 1 && wd.stride() == lhs_size &&
      wd.base_dilation() == lhs_size - 1) {
    return true;
  }

  return false;
}

/* static */ DotConvolutionDimsInfo ParseConvolutionDimsInfo(
    const HloInstruction* conv) {
  CHECK_EQ(conv->opcode(), HloOpcode::kConvolution);
  const auto& conv_dims = conv->convolution_dimension_numbers();
  DotConvolutionDimsInfo dims;
  dims.lhs_non_contracting_dims.push_back(
      {conv_dims.input_batch_dimension(), -1,
       conv_dims.output_batch_dimension(), -1});
  dims.rhs_non_contracting_dims.push_back(
      {-1, conv_dims.kernel_output_feature_dimension(),
       conv_dims.output_feature_dimension(), -1});
  dims.contracting_dims.push_back({conv_dims.input_feature_dimension(),
                                   conv_dims.kernel_input_feature_dimension(),
                                   -1, -1});

  for (int64 i = 0; i < conv_dims.input_spatial_dimensions_size(); ++i) {
    int64 lhs = conv_dims.input_spatial_dimensions(i);
    int64 lhs_size = conv->operand(0)->shape().dimensions(lhs);
    int64 rhs = conv_dims.kernel_spatial_dimensions(i);
    int64 rhs_size = conv->operand(1)->shape().dimensions(rhs);
    int64 output = conv_dims.output_spatial_dimensions(i);
    const auto& wd = conv->window().dimensions(i);
    if (ConvSpatialDimensionIsParallel(wd, lhs_size)) {
      dims.batch_dims.push_back({lhs, rhs, output, i});
    } else if (lhs_size == wd.size() && wd.base_dilation() == 1 &&
               wd.window_dilation() == 1 && wd.padding_high() == 0 &&
               wd.padding_low() == 0 && !wd.window_reversal()) {
      // A contracting dimension be represented as a spatial dimension with
      // window size C (contracting dimension size). Stride can be any size
      // since there is only one window.
      dims.contracting_dims.push_back({lhs, rhs, output, i});
    } else if (wd.stride() == 1 && wd.window_dilation() == 1 &&
               wd.base_dilation() == 1) {
      if (rhs_size == 1 && wd.size() == 1 && wd.padding_high() == 0 &&
          wd.padding_low() == 0 && !wd.window_reversal()) {
        // A LHS non-contracting dimension can be represented as a spatial
        // dimension with window size 1.
        dims.lhs_non_contracting_dims.push_back({lhs, rhs, output, i});
      } else if (lhs_size == 1 && wd.size() == rhs_size &&
                 wd.padding_high() == rhs_size - 1 &&
                 wd.padding_low() == rhs_size - 1 && wd.window_reversal()) {
        // A RHS non-contracting dimension can be represented as a spatial
        // dimension with window size N (non-contracting dimension size), low
        // padding N - 1,  high padding N - 1 and window reversal.
        dims.rhs_non_contracting_dims.push_back({lhs, rhs, output, i});
      } else {
        dims.conv_spatial_dims.push_back({lhs, rhs, output, i});
      }
    } else {
      dims.conv_spatial_dims.push_back({lhs, rhs, output, i});
    }
  }

  return dims;
}

StatusOr<std::unique_ptr<HloInstruction>>
CreateShardedConvForDotGeneralConvolution(
    const HloInstruction& conv, const DotConvolutionDimsInfo& dot_dnums,
    HloInstruction* sharded_lhs_hlo, HloInstruction* sharded_rhs_hlo) {
  CHECK_EQ(conv.opcode(), HloOpcode::kConvolution);
  const auto& conv_dnums = conv.convolution_dimension_numbers();
  auto window = conv.window();
  for (const auto& dim : dot_dnums.batch_dims) {
    auto wd = window.mutable_dimensions(dim.spatial_dim);
    wd->set_size(sharded_lhs_hlo->shape().dimensions(
        conv_dnums.input_spatial_dimensions(dim.spatial_dim)));
    wd->set_stride(std::max<int64>(1, wd->size() - 1));
    wd->set_base_dilation(wd->size());
  }
  for (const auto& dim : dot_dnums.contracting_dims) {
    if (dim.spatial_dim < 0) {
      continue;
    }
    auto wd = window.mutable_dimensions(dim.spatial_dim);
    wd->set_size(sharded_lhs_hlo->shape().dimensions(
        conv_dnums.input_spatial_dimensions(dim.spatial_dim)));
  }
  for (const auto& dim : dot_dnums.rhs_non_contracting_dims) {
    if (dim.spatial_dim < 0) {
      continue;
    }
    auto wd = window.mutable_dimensions(dim.spatial_dim);
    wd->set_size(sharded_rhs_hlo->shape().dimensions(
        conv_dnums.kernel_spatial_dimensions(dim.spatial_dim)));
    wd->set_padding_high(wd->size() - 1);
    wd->set_padding_low(wd->size() - 1);
  }
  TF_ASSIGN_OR_RETURN(
      Shape sharded_conv_shape,
      ShapeInference::InferConvolveShape(
          sharded_lhs_hlo->shape(), sharded_rhs_hlo->shape(),
          /*feature_group_count=*/conv.feature_group_count(),
          /*batch_group_count=*/conv.batch_group_count(), window, conv_dnums));
  *sharded_conv_shape.mutable_layout() = conv.shape().layout();
  return HloInstruction::CreateConvolve(
      sharded_conv_shape, sharded_lhs_hlo, sharded_rhs_hlo,
      /*feature_group_count=*/conv.feature_group_count(),
      /*batch_group_count=*/conv.batch_group_count(), window, conv_dnums,
      conv.precision_config());
}

DotConvolutionDimsInfo ParseDotGeneralFromDot(const HloInstruction* dot) {
  const auto& dot_dim_numbs = dot->dot_dimension_numbers();
  dot_as_convolution_util::DotConvolutionDimsInfo dnums;
  for (int64 i = 0; i < dot_dim_numbs.lhs_batch_dimensions().size(); ++i) {
    dnums.batch_dims.emplace_back();
    dnums.batch_dims.back().lhs = dot_dim_numbs.lhs_batch_dimensions(i);
    dnums.batch_dims.back().rhs = dot_dim_numbs.rhs_batch_dimensions(i);
    dnums.batch_dims.back().output = i;
    dnums.batch_dims.back().spatial_dim = -1;
  }
  for (int64 i = 0; i < dot_dim_numbs.lhs_contracting_dimensions().size();
       ++i) {
    dnums.contracting_dims.emplace_back();
    dnums.contracting_dims.back().lhs =
        dot_dim_numbs.lhs_contracting_dimensions(i);
    dnums.contracting_dims.back().rhs =
        dot_dim_numbs.rhs_contracting_dimensions(i);
    dnums.contracting_dims.back().output = -1;
    dnums.contracting_dims.back().spatial_dim = -1;
  }
  for (int64 i = 0; i < dot->operand(0)->shape().rank(); ++i) {
    if (!absl::c_linear_search(dot_dim_numbs.lhs_batch_dimensions(), i) &&
        !absl::c_linear_search(dot_dim_numbs.lhs_contracting_dimensions(), i)) {
      dnums.lhs_non_contracting_dims.emplace_back();
      dnums.lhs_non_contracting_dims.back().lhs = i;
      dnums.lhs_non_contracting_dims.back().rhs = -1;
      dnums.lhs_non_contracting_dims.back().output =
          dot_dim_numbs.lhs_batch_dimensions_size() +
          dnums.lhs_non_contracting_dims.size() - 1;
      dnums.lhs_non_contracting_dims.back().spatial_dim = -1;
    }
  }
  for (int64 i = 0; i < dot->operand(1)->shape().rank(); ++i) {
    if (!absl::c_linear_search(dot_dim_numbs.rhs_batch_dimensions(), i) &&
        !absl::c_linear_search(dot_dim_numbs.rhs_contracting_dimensions(), i)) {
      dnums.rhs_non_contracting_dims.emplace_back();
      dnums.rhs_non_contracting_dims.back().lhs = -1;
      dnums.rhs_non_contracting_dims.back().rhs = i;
      dnums.rhs_non_contracting_dims.back().output =
          dot_dim_numbs.lhs_batch_dimensions_size() +
          dnums.lhs_non_contracting_dims.size() +
          dnums.rhs_non_contracting_dims.size() - 1;
      dnums.rhs_non_contracting_dims.back().spatial_dim = -1;
    }
  }
  return dnums;
}

}  // namespace dot_as_convolution_util
}  // namespace xla
<|endoftext|>


<commit_before>#include <string>
#include <iostream>
#include "dirent.h"

using namespace std;

int main()
{
	DIR *dir;
	struct dirent *ent;

	if ((dir = opendir ("\\lists\\")) != NULL) {
		while ((ent = readdir (dir)) != NULL) {
			cout << ent->d_name << endl;
		}
		closedir(dir);
	}
	else
	{
		perror ("");
		return EXIT_FAILURE;
	}
	return (0);
}
<commit_msg>Delete directoryIteratorTest2.cpp<commit_after><|endoftext|>


<commit_before>#include "Header.h"

#include "Common/StringUtils.h"
#include "Common/TimeUtils.h"

using namespace HTTP;

/**Parses a string containing key=value pairs in HTTP header format. Supports value quoting, without quote escape.
Sample input stuff; key1=value1; key2="value2"
@param ParamConsumerType A functor with the following signature:
	Func(const CharType *KeyBegin, const CharType *KeyEnd, const CharType *ValueBegin, const CharType *ValueEnd)
	Note that ValueBegin and ValueEnd can be nullptr, if the given key
*/
template<class ParamConsumerType, class CharType, CharType Separator>
void ParseDelimitedKeyValue(const CharType *Source, ParamConsumerType Consumer)
{
	const CharType *CurrPos=Source;
	const CharType *KeyBegin=NULL, *KeyEnd=NULL;
	const CharType *ValueBegin=NULL;

	enum PARSE_STATE
	{
		PS_ZERO, //Searching for key.
		PS_KEY, //Searching for key end.
		PS_SEPSEARCH, //Searching for Separator.
		PS_VALSEARCH, //Searching for value.
		PS_VAL, //Searching for value end.
		PS_QUOTEDVAL, //Searching for value end in quoted value.
	} CurrState=PS_ZERO;

	CharType CurrVal;
	while (true)
	{
		CurrVal=*CurrPos;
		if (!CurrVal)
			break;

		switch (CurrState)
		{
		case PS_ZERO:
			if ((!UD::StringUtils::IsWS(CurrVal)) && (CurrVal!=';'))
			{
				KeyBegin=CurrPos;
				CurrState=PS_KEY;
			}
			break;
		case PS_KEY:
			if (UD::StringUtils::IsWS(CurrVal))
			{
				KeyEnd=CurrPos;
				CurrState=PS_SEPSEARCH;
			}
			else if (CurrVal==Separator)
			{
				KeyEnd=CurrPos;
				CurrState=PS_VALSEARCH;
			}
			else if (CurrVal==';')
			{
				Consumer(KeyBegin,CurrPos,nullptr,nullptr);
				CurrState=PS_ZERO;
			}
			break;
		case PS_SEPSEARCH:
			if (CurrVal==Separator)
				CurrState=PS_VALSEARCH;
			else if (CurrVal==';')
			{
				Consumer(KeyBegin,KeyEnd,nullptr,nullptr);
				CurrState=PS_ZERO;
			}
			else if (!UD::StringUtils::IsWS(CurrVal))
			{
				//This is something weird, like: "Key1 Key2...". Let's skip Key1, and start again from Key2.
				KeyBegin=CurrPos;
				CurrState=PS_KEY;
			}
			break;
		case PS_VALSEARCH:
			if (!UD::StringUtils::IsWS(CurrVal))
			{
				ValueBegin=CurrPos;
				if (CurrVal=='"')
					CurrState=PS_QUOTEDVAL;
				else
					CurrState=PS_VAL;
			}
			else if (UD::StringUtils::IsNewLine(CurrVal))
			{
				//Empty value.
				Consumer(KeyBegin,KeyEnd,CurrPos,CurrPos);
				CurrState=PS_ZERO;
			}
			break;
		case PS_VAL:
			if ((UD::StringUtils::IsWS(CurrVal)) || (CurrVal==';'))
			{
				//End of value.
				Consumer(KeyBegin,KeyEnd,ValueBegin,CurrPos);
				CurrState=PS_ZERO;
			}
			break;
		case PS_QUOTEDVAL:
			if (CurrVal=='"')
			{
				//End of quoted value (ValueBegin points to the '"').
				Consumer(KeyBegin,KeyEnd,ValueBegin+1,CurrPos);
				CurrState=PS_ZERO;
			}
			break;
		default:
			break;
		}

		CurrPos++;
	}

	//We might have some work left.
	switch (CurrState)
	{
	case PS_VAL:
		//Output the last value.
		Consumer(KeyBegin,KeyEnd,ValueBegin,CurrPos);
		break;
	case PS_QUOTEDVAL:
		//Output the last value (quoted, but quote not closed).
		Consumer(KeyBegin,KeyEnd,ValueBegin+1,CurrPos);
		break;
	default:
		break;
	}
}

template<class ParamConsumerType>
inline void ParseDelimitedKeyValue(const char *Source, ParamConsumerType Consumer) { ParseDelimitedKeyValue<ParamConsumerType,char,'='>(Source,Consumer); }

struct SingleKeyExtractor
{
	SingleKeyExtractor(const std::string &KeyName, std::string &ValTargetStr) : Key(KeyName), Target(ValTargetStr)
	{ }

	void operator()(const char *KeyBegin, const char *KeyEnd, const char *ValueBegin, const char *ValueEnd)
	{
		if ((ValueBegin) && (UD::StringUtils::IsEqual(Key,KeyBegin,KeyEnd)))
			Target.assign(ValueBegin,ValueEnd);
	}

private:
	const std::string &Key;
	std::string &Target;
};

struct ContentDisposExtractor
{
	ContentDisposExtractor(std::string &NameStr, std::string &FNStr) : NameTarget(NameStr), FNTarget(FNStr)
	{ }

	void operator()(const char *KeyBegin, const char *KeyEnd, const char *ValueBegin, const char *ValueEnd)
	{
		if (ValueBegin)
		{
			if (UD::StringUtils::IsEqual(NameKey,KeyBegin,KeyEnd))
				NameTarget.assign(ValueBegin,ValueEnd);
			else if (UD::StringUtils::IsEqual(FNKey,KeyBegin,KeyEnd))
				FNTarget.assign(ValueBegin,ValueEnd);
		}
	}

private:
	static const std::string NameKey, FNKey;
	std::string &NameTarget, &FNTarget;
};

const std::string ContentDisposExtractor::NameKey="name", ContentDisposExtractor::FNKey="filename";

const std::string Header::BoundaryParamName("boundary");

boost::unordered_map<std::string,HEADERNAME> Header::HeaderNameMap;
bool Header::IsHeaderNameInit=Header::InitHeaderNameMap();

Header::Header(char *LineBegin, char *LineEnd)
{
	if (ExtractHeader(LineBegin,LineEnd,(char **)&Name,(char **)&Value))
		IntName=ParseHeader(Name);
	else
		IntName=HN_UNKNOWN;
}

Header::Header(char *LineBegin, char *LineEnd, SkipParseOption) : IntName(HN_UNKNOWN)
{
	ExtractHeader(LineBegin,LineEnd,(char **)&Name,(char **)&Value);
}

CONTENTTYPE Header::GetContentType(std::string &OutBoundary) const
{
	if (IntName!=HN_CONTENT_TYPE)
		return CT_UNKNOWN;

	if (const char *SCPos=strchr(Value,';'))
	{
		if (UD::StringUtils::CmpI("multipart/form-data",Value,SCPos)==0)
		{
			OutBoundary.clear();
			ParseDelimitedKeyValue(SCPos,SingleKeyExtractor(BoundaryParamName,OutBoundary));
			return !OutBoundary.empty() ? CT_FORM_MULTIPART : CT_UNKNOWN;
		}
	}
	else
	{
		if (UD::StringUtils::CmpI(Value,"application/x-www-form-urlencoded")==0)
			return CT_URL_ENCODED;
	}

	return CT_UNKNOWN;
}

void Header::ParseContentDisposition(std::string &OutName, std::string &OutFileName) const
{
	if (IntName==HN_CONTENT_DISPOSITION)
		ParseDelimitedKeyValue(Value,ContentDisposExtractor(OutName,OutFileName));
	else
	{
		OutName.clear();
		OutFileName.clear();
	}
}

bool Header::IsConnectionClose() const
{
	return strcmp(Value,"close")==0;
}

time_t Header::GetDateTime() const
{
	//                       0         1         2
	//                       01234567890123456789012345678
	//Sample RFC 1123 date: "Sun, 06 Nov 1994 08:49:37 GMT", strlen: 29
	//WDay values: "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun"
	//Month values: "Jan" | "Feb" | "Mar" | "Apr" | "May" | "Jun" | "Jul" | "Aug" | "Sep" | "Oct" | "Nov" | "Dec"

	if (strlen(Value)!=DateStringLength)
		throw FormatException("DateTime has invalid length");

	tm TM;
	TM.tm_isdst=0; TM.tm_wday=0; TM.tm_yday=0;
	TM.tm_mday=atoi(Value + 5);
	TM.tm_year=atoi(Value + 12) - 1900;
	TM.tm_hour=atoi(Value + 17);
	TM.tm_min=atoi(Value + 20);
	TM.tm_sec=atoi(Value + 23);

	TM.tm_mon=-1;
	switch (*(Value + 8))
	{
	case 'A': //Apr, Aug
		if (*(Value + 9)=='p')
			TM.tm_mon=3; //Apr
		else if (*(Value + 9)=='u')
			TM.tm_mon=7; //Aug
		break;
	case 'D': //Dec
		TM.tm_mon=11;
		break;
	case 'F': //Feb
		TM.tm_mon=2;
		break;
	case 'J': //Jan, Jun, Jul
		if (*(Value + 9)=='a')
			TM.tm_mon=0; //Jan
		else if (*(Value + 10)=='l')
			TM.tm_mon=6; //Jul
		else if (*(Value + 10)=='n')
			TM.tm_mon=5; //Jun
		break;
	case 'M': //Mar, May
		if (*(Value + 10)=='r')
			TM.tm_mon=2; //Mar
		else if (*(Value + 10)=='y')
			TM.tm_mon=4; //May
		break;
	case 'N': //Nov
		TM.tm_mon=10;
		break;
	case 'O': //Oct
		TM.tm_mon=9;
		break;
	case 'S': //Sep
		TM.tm_mon=8;
		break;
	}

	if ((TM.tm_year==0) || (TM.tm_mon==1))
		throw FormatException("DateTime is invalid");

	time_t RetTime=UD::TimeUtils::TimeGM(&TM);
	if (RetTime!=-1)
		return RetTime;
	else
		throw FormatException("DateTime is invalid");
}

long long Header::GetLongLong() const
{
	char *EndPtr;
#ifdef _MSC_VER
	long long RetVal=_strtoi64(Value,&EndPtr,10);
#else
	long long RetVal=strtoll(Value,&EndPtr,10);
#endif
	if (EndPtr!=Value)
		return RetVal;
	else
		throw FormatException("Cannot parse LongLong value");
}

unsigned long long Header::GetULongLong() const
{
	char *EndPtr;
#ifdef _MSC_VER
	unsigned long long RetVal=_strtoui64(Value,&EndPtr,10);
#else
	unsigned long long RetVal=strtoull(Value,&EndPtr,10);
#endif
	if (EndPtr!=Value)
		return RetVal;
	else
		throw FormatException("Cannot parse ULongLong value");
}

HEADERNAME Header::ParseHeader(const char *Name)
{
	boost::unordered_map<std::string,HEADERNAME>::const_iterator FindI=HeaderNameMap.find(Name);
	if (FindI!=HeaderNameMap.end())
		return FindI->second;
	else
		return HN_UNKNOWN;
}

const std::string &Header::GetHeaderName(HEADERNAME Name)
{
	switch (Name)
	{
	case HN_HOST: { static const std::string HeaderStr("host"); return HeaderStr; }
	case HN_CONNECTION: { static const std::string HeaderStr("connection"); return HeaderStr; }
	case HN_CONTENT_DISPOSITION: { static const std::string HeaderStr("content-disposition"); return HeaderStr; }
	case HN_CONTENT_TYPE: { static const std::string HeaderStr("content-type"); return HeaderStr; }
	case HN_CONTENT_LENGTH: { static const std::string HeaderStr("content-length"); return HeaderStr; }
	case HN_CONTENT_ENCODING: { static const std::string HeaderStr("content-encoding"); return HeaderStr; }
	case HN_USER_AGENT: { static const std::string HeaderStr("user-agent"); return HeaderStr; }
	case HN_IF_MOD_SINCE: { static const std::string HeaderStr("if-modified-since"); return HeaderStr; }
	case HH_ORIGIN: { static const std::string HeaderStr("origin"); return HeaderStr; }
	case HH_UPGRADE: { static const std::string HeaderStr("upgrade"); return HeaderStr; }
	case HH_SEC_WEBSOCKET_KEY: { static const std::string HeaderStr("sec-websocket-key"); return HeaderStr; }
	case HH_SEC_WEBSCOKET_VERSION: { static const std::string HeaderStr("sec-websocket-version"); return HeaderStr; }
	case HH_SEC_WEBSOCKET_PROTOCOL: { static const std::string HeaderStr("sec-websocket-protocol"); return HeaderStr; }
	case HN_LAST_MODIFIED: { static const std::string HeaderStr("last-modified"); return HeaderStr; }
	case HN_LOCATION: { static const std::string HeaderStr("location"); return HeaderStr; }
	case HH_SEC_WEBSOCKET_ACCEPT: { static const std::string HeaderStr("sec-websocket-accept"); return HeaderStr; }
	default: { static const std::string HeaderStr(""); return HeaderStr; }
	}
}

char *Header::ExtractHeader(char *LineBegin, char *LineEnd, char **OutName, char **OutValue)
{
	*OutName=LineBegin;
	*OutValue=nullptr;
	while (LineBegin!=LineEnd)
	{
		char CurrVal=*LineBegin;
		if ((CurrVal>='A') && (CurrVal<='Z'))
			*LineBegin=CurrVal-'A'+'a';
		else if (CurrVal==':')
		{
			*LineBegin='\0';
			LineBegin++;
			break;
		}

		LineBegin++;
	}

	while (LineBegin!=LineEnd)
	{
		if (*LineBegin!=' ')
		{
			*OutValue=LineBegin;
			break;
		}
		else
			LineBegin++;
	}

	while (LineBegin!=LineEnd)
	{
		if (*LineBegin=='\r')
		{
			*LineBegin++='\0';
			return LineBegin;
		}
		else
			LineBegin++;
	}

	return nullptr;
}

void Header::FormatDateTime(time_t Timestamp, char *TargetBuff)
{
	tm TM;
	if (!UD::TimeUtils::GMTime(&Timestamp,&TM))
		strftime(TargetBuff,30,"%a, %d %b %Y %H:%M:%S GMT",&TM);
	else
		*TargetBuff='\0';
}

bool Header::InitHeaderNameMap()
{
	for (unsigned int x=HN_UNKNOWN + 1; x!=HN_NOTUSED; ++x)
		AddToHeaderMap((HEADERNAME)x);

	return true;
}
<commit_msg>Header::GetContentType: application/x-www-form-urlencoded parse fix<commit_after>#include "Header.h"

#include "Common/StringUtils.h"
#include "Common/TimeUtils.h"

using namespace HTTP;

/**Parses a string containing key=value pairs in HTTP header format. Supports value quoting, without quote escape.
Sample input stuff; key1=value1; key2="value2"
@param ParamConsumerType A functor with the following signature:
	Func(const CharType *KeyBegin, const CharType *KeyEnd, const CharType *ValueBegin, const CharType *ValueEnd)
	Note that ValueBegin and ValueEnd can be nullptr, if the given key
*/
template<class ParamConsumerType, class CharType, CharType Separator>
void ParseDelimitedKeyValue(const CharType *Source, ParamConsumerType Consumer)
{
	const CharType *CurrPos=Source;
	const CharType *KeyBegin=NULL, *KeyEnd=NULL;
	const CharType *ValueBegin=NULL;

	enum PARSE_STATE
	{
		PS_ZERO, //Searching for key.
		PS_KEY, //Searching for key end.
		PS_SEPSEARCH, //Searching for Separator.
		PS_VALSEARCH, //Searching for value.
		PS_VAL, //Searching for value end.
		PS_QUOTEDVAL, //Searching for value end in quoted value.
	} CurrState=PS_ZERO;

	CharType CurrVal;
	while (true)
	{
		CurrVal=*CurrPos;
		if (!CurrVal)
			break;

		switch (CurrState)
		{
		case PS_ZERO:
			if ((!UD::StringUtils::IsWS(CurrVal)) && (CurrVal!=';'))
			{
				KeyBegin=CurrPos;
				CurrState=PS_KEY;
			}
			break;
		case PS_KEY:
			if (UD::StringUtils::IsWS(CurrVal))
			{
				KeyEnd=CurrPos;
				CurrState=PS_SEPSEARCH;
			}
			else if (CurrVal==Separator)
			{
				KeyEnd=CurrPos;
				CurrState=PS_VALSEARCH;
			}
			else if (CurrVal==';')
			{
				Consumer(KeyBegin,CurrPos,nullptr,nullptr);
				CurrState=PS_ZERO;
			}
			break;
		case PS_SEPSEARCH:
			if (CurrVal==Separator)
				CurrState=PS_VALSEARCH;
			else if (CurrVal==';')
			{
				Consumer(KeyBegin,KeyEnd,nullptr,nullptr);
				CurrState=PS_ZERO;
			}
			else if (!UD::StringUtils::IsWS(CurrVal))
			{
				//This is something weird, like: "Key1 Key2...". Let's skip Key1, and start again from Key2.
				KeyBegin=CurrPos;
				CurrState=PS_KEY;
			}
			break;
		case PS_VALSEARCH:
			if (!UD::StringUtils::IsWS(CurrVal))
			{
				ValueBegin=CurrPos;
				if (CurrVal=='"')
					CurrState=PS_QUOTEDVAL;
				else
					CurrState=PS_VAL;
			}
			else if (UD::StringUtils::IsNewLine(CurrVal))
			{
				//Empty value.
				Consumer(KeyBegin,KeyEnd,CurrPos,CurrPos);
				CurrState=PS_ZERO;
			}
			break;
		case PS_VAL:
			if ((UD::StringUtils::IsWS(CurrVal)) || (CurrVal==';'))
			{
				//End of value.
				Consumer(KeyBegin,KeyEnd,ValueBegin,CurrPos);
				CurrState=PS_ZERO;
			}
			break;
		case PS_QUOTEDVAL:
			if (CurrVal=='"')
			{
				//End of quoted value (ValueBegin points to the '"').
				Consumer(KeyBegin,KeyEnd,ValueBegin+1,CurrPos);
				CurrState=PS_ZERO;
			}
			break;
		default:
			break;
		}

		CurrPos++;
	}

	//We might have some work left.
	switch (CurrState)
	{
	case PS_VAL:
		//Output the last value.
		Consumer(KeyBegin,KeyEnd,ValueBegin,CurrPos);
		break;
	case PS_QUOTEDVAL:
		//Output the last value (quoted, but quote not closed).
		Consumer(KeyBegin,KeyEnd,ValueBegin+1,CurrPos);
		break;
	default:
		break;
	}
}

template<class ParamConsumerType>
inline void ParseDelimitedKeyValue(const char *Source, ParamConsumerType Consumer) { ParseDelimitedKeyValue<ParamConsumerType,char,'='>(Source,Consumer); }

struct SingleKeyExtractor
{
	SingleKeyExtractor(const std::string &KeyName, std::string &ValTargetStr) : Key(KeyName), Target(ValTargetStr)
	{ }

	void operator()(const char *KeyBegin, const char *KeyEnd, const char *ValueBegin, const char *ValueEnd)
	{
		if ((ValueBegin) && (UD::StringUtils::IsEqual(Key,KeyBegin,KeyEnd)))
			Target.assign(ValueBegin,ValueEnd);
	}

private:
	const std::string &Key;
	std::string &Target;
};

struct ContentDisposExtractor
{
	ContentDisposExtractor(std::string &NameStr, std::string &FNStr) : NameTarget(NameStr), FNTarget(FNStr)
	{ }

	void operator()(const char *KeyBegin, const char *KeyEnd, const char *ValueBegin, const char *ValueEnd)
	{
		if (ValueBegin)
		{
			if (UD::StringUtils::IsEqual(NameKey,KeyBegin,KeyEnd))
				NameTarget.assign(ValueBegin,ValueEnd);
			else if (UD::StringUtils::IsEqual(FNKey,KeyBegin,KeyEnd))
				FNTarget.assign(ValueBegin,ValueEnd);
		}
	}

private:
	static const std::string NameKey, FNKey;
	std::string &NameTarget, &FNTarget;
};

const std::string ContentDisposExtractor::NameKey="name", ContentDisposExtractor::FNKey="filename";

const std::string Header::BoundaryParamName("boundary");

boost::unordered_map<std::string,HEADERNAME> Header::HeaderNameMap;
bool Header::IsHeaderNameInit=Header::InitHeaderNameMap();

Header::Header(char *LineBegin, char *LineEnd)
{
	if (ExtractHeader(LineBegin,LineEnd,(char **)&Name,(char **)&Value))
		IntName=ParseHeader(Name);
	else
		IntName=HN_UNKNOWN;
}

Header::Header(char *LineBegin, char *LineEnd, SkipParseOption) : IntName(HN_UNKNOWN)
{
	ExtractHeader(LineBegin,LineEnd,(char **)&Name,(char **)&Value);
}

CONTENTTYPE Header::GetContentType(std::string &OutBoundary) const
{
	if (IntName!=HN_CONTENT_TYPE)
		return CT_UNKNOWN;

	if (const char *SCPos=strchr(Value,';'))
	{
		if (UD::StringUtils::CmpI("multipart/form-data",Value,SCPos)==0)
		{
			OutBoundary.clear();
			ParseDelimitedKeyValue(SCPos,SingleKeyExtractor(BoundaryParamName,OutBoundary));
			return !OutBoundary.empty() ? CT_FORM_MULTIPART : CT_UNKNOWN;
		}
		else if (UD::StringUtils::CmpI("application/x-www-form-urlencoded",Value,SCPos)==0)
			return CT_URL_ENCODED;
	}
	else
	{
		if (UD::StringUtils::CmpI(Value,"application/x-www-form-urlencoded")==0)
			return CT_URL_ENCODED;
	}

	return CT_UNKNOWN;
}

void Header::ParseContentDisposition(std::string &OutName, std::string &OutFileName) const
{
	if (IntName==HN_CONTENT_DISPOSITION)
		ParseDelimitedKeyValue(Value,ContentDisposExtractor(OutName,OutFileName));
	else
	{
		OutName.clear();
		OutFileName.clear();
	}
}

bool Header::IsConnectionClose() const
{
	return strcmp(Value,"close")==0;
}

time_t Header::GetDateTime() const
{
	//                       0         1         2
	//                       01234567890123456789012345678
	//Sample RFC 1123 date: "Sun, 06 Nov 1994 08:49:37 GMT", strlen: 29
	//WDay values: "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun"
	//Month values: "Jan" | "Feb" | "Mar" | "Apr" | "May" | "Jun" | "Jul" | "Aug" | "Sep" | "Oct" | "Nov" | "Dec"

	if (strlen(Value)!=DateStringLength)
		throw FormatException("DateTime has invalid length");

	tm TM;
	TM.tm_isdst=0; TM.tm_wday=0; TM.tm_yday=0;
	TM.tm_mday=atoi(Value + 5);
	TM.tm_year=atoi(Value + 12) - 1900;
	TM.tm_hour=atoi(Value + 17);
	TM.tm_min=atoi(Value + 20);
	TM.tm_sec=atoi(Value + 23);

	TM.tm_mon=-1;
	switch (*(Value + 8))
	{
	case 'A': //Apr, Aug
		if (*(Value + 9)=='p')
			TM.tm_mon=3; //Apr
		else if (*(Value + 9)=='u')
			TM.tm_mon=7; //Aug
		break;
	case 'D': //Dec
		TM.tm_mon=11;
		break;
	case 'F': //Feb
		TM.tm_mon=2;
		break;
	case 'J': //Jan, Jun, Jul
		if (*(Value + 9)=='a')
			TM.tm_mon=0; //Jan
		else if (*(Value + 10)=='l')
			TM.tm_mon=6; //Jul
		else if (*(Value + 10)=='n')
			TM.tm_mon=5; //Jun
		break;
	case 'M': //Mar, May
		if (*(Value + 10)=='r')
			TM.tm_mon=2; //Mar
		else if (*(Value + 10)=='y')
			TM.tm_mon=4; //May
		break;
	case 'N': //Nov
		TM.tm_mon=10;
		break;
	case 'O': //Oct
		TM.tm_mon=9;
		break;
	case 'S': //Sep
		TM.tm_mon=8;
		break;
	}

	if ((TM.tm_year==0) || (TM.tm_mon==1))
		throw FormatException("DateTime is invalid");

	time_t RetTime=UD::TimeUtils::TimeGM(&TM);
	if (RetTime!=-1)
		return RetTime;
	else
		throw FormatException("DateTime is invalid");
}

long long Header::GetLongLong() const
{
	char *EndPtr;
#ifdef _MSC_VER
	long long RetVal=_strtoi64(Value,&EndPtr,10);
#else
	long long RetVal=strtoll(Value,&EndPtr,10);
#endif
	if (EndPtr!=Value)
		return RetVal;
	else
		throw FormatException("Cannot parse LongLong value");
}

unsigned long long Header::GetULongLong() const
{
	char *EndPtr;
#ifdef _MSC_VER
	unsigned long long RetVal=_strtoui64(Value,&EndPtr,10);
#else
	unsigned long long RetVal=strtoull(Value,&EndPtr,10);
#endif
	if (EndPtr!=Value)
		return RetVal;
	else
		throw FormatException("Cannot parse ULongLong value");
}

HEADERNAME Header::ParseHeader(const char *Name)
{
	boost::unordered_map<std::string,HEADERNAME>::const_iterator FindI=HeaderNameMap.find(Name);
	if (FindI!=HeaderNameMap.end())
		return FindI->second;
	else
		return HN_UNKNOWN;
}

const std::string &Header::GetHeaderName(HEADERNAME Name)
{
	switch (Name)
	{
	case HN_HOST: { static const std::string HeaderStr("host"); return HeaderStr; }
	case HN_CONNECTION: { static const std::string HeaderStr("connection"); return HeaderStr; }
	case HN_CONTENT_DISPOSITION: { static const std::string HeaderStr("content-disposition"); return HeaderStr; }
	case HN_CONTENT_TYPE: { static const std::string HeaderStr("content-type"); return HeaderStr; }
	case HN_CONTENT_LENGTH: { static const std::string HeaderStr("content-length"); return HeaderStr; }
	case HN_CONTENT_ENCODING: { static const std::string HeaderStr("content-encoding"); return HeaderStr; }
	case HN_USER_AGENT: { static const std::string HeaderStr("user-agent"); return HeaderStr; }
	case HN_IF_MOD_SINCE: { static const std::string HeaderStr("if-modified-since"); return HeaderStr; }
	case HH_ORIGIN: { static const std::string HeaderStr("origin"); return HeaderStr; }
	case HH_UPGRADE: { static const std::string HeaderStr("upgrade"); return HeaderStr; }
	case HH_SEC_WEBSOCKET_KEY: { static const std::string HeaderStr("sec-websocket-key"); return HeaderStr; }
	case HH_SEC_WEBSCOKET_VERSION: { static const std::string HeaderStr("sec-websocket-version"); return HeaderStr; }
	case HH_SEC_WEBSOCKET_PROTOCOL: { static const std::string HeaderStr("sec-websocket-protocol"); return HeaderStr; }
	case HN_LAST_MODIFIED: { static const std::string HeaderStr("last-modified"); return HeaderStr; }
	case HN_LOCATION: { static const std::string HeaderStr("location"); return HeaderStr; }
	case HH_SEC_WEBSOCKET_ACCEPT: { static const std::string HeaderStr("sec-websocket-accept"); return HeaderStr; }
	default: { static const std::string HeaderStr(""); return HeaderStr; }
	}
}

char *Header::ExtractHeader(char *LineBegin, char *LineEnd, char **OutName, char **OutValue)
{
	*OutName=LineBegin;
	*OutValue=nullptr;
	while (LineBegin!=LineEnd)
	{
		char CurrVal=*LineBegin;
		if ((CurrVal>='A') && (CurrVal<='Z'))
			*LineBegin=CurrVal-'A'+'a';
		else if (CurrVal==':')
		{
			*LineBegin='\0';
			LineBegin++;
			break;
		}

		LineBegin++;
	}

	while (LineBegin!=LineEnd)
	{
		if (*LineBegin!=' ')
		{
			*OutValue=LineBegin;
			break;
		}
		else
			LineBegin++;
	}

	while (LineBegin!=LineEnd)
	{
		if (*LineBegin=='\r')
		{
			*LineBegin++='\0';
			return LineBegin;
		}
		else
			LineBegin++;
	}

	return nullptr;
}

void Header::FormatDateTime(time_t Timestamp, char *TargetBuff)
{
	tm TM;
	if (!UD::TimeUtils::GMTime(&Timestamp,&TM))
		strftime(TargetBuff,30,"%a, %d %b %Y %H:%M:%S GMT",&TM);
	else
		*TargetBuff='\0';
}

bool Header::InitHeaderNameMap()
{
	for (unsigned int x=HN_UNKNOWN + 1; x!=HN_NOTUSED; ++x)
		AddToHeaderMap((HEADERNAME)x);

	return true;
}
<|endoftext|>