<commit_before>#include <catch.hpp>

#include <regex>
#include "test_data.hpp"
#include "libslic3r.h"
#include "GCodeReader.hpp"

using namespace Slic3r::Test;
using namespace Slic3r;

std::regex perimeters_regex("G1 X[-0-9.]* Y[-0-9.]* E[-0-9.]* ; perimeter");
std::regex infill_regex("G1 X[-0-9.]* Y[-0-9.]* E[-0-9.]* ; infill");
std::regex skirt_regex("G1 X[-0-9.]* Y[-0-9.]* E[-0-9.]* ; skirt");

SCENARIO( "PrintGCode basic functionality", "[!mayfail]") {
    GIVEN("A default configuration and a print test object") {
        auto config {Slic3r::Config::new_from_defaults()};
        auto gcode {std::stringstream("")};

        WHEN("the output is executed with no support material") {
            config->set("first_layer_extrusion_width", 0);
            config->set("gcode_comments", true);
            config->set("start_gcode", "");
            Slic3r::Model model;
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            print->process();
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("Some text output is generated.") {
                REQUIRE(exported.size() > 0);
            }
            THEN("Exported text contains slic3r version") {
                REQUIRE(exported.find(SLIC3R_VERSION) != std::string::npos);
            }
            THEN("Exported text contains git commit id") {
                REQUIRE(exported.find("; Git Commit") != std::string::npos);
                REQUIRE(exported.find(BUILD_COMMIT) != std::string::npos);
            }
            THEN("Exported text contains extrusion statistics.") {
                REQUIRE(exported.find("; external perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; top solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; support material extrusion width") == std::string::npos);
                REQUIRE(exported.find("; first layer extrusion width") == std::string::npos);
            }

            THEN("GCode preamble is emitted.") {
                REQUIRE(exported.find("G21 ; set units to millimeters") != std::string::npos);
            }

            THEN("Config options emitted for print config, default region config, default object config") {
                REQUIRE(exported.find("; first_layer_temperature") != std::string::npos);
                REQUIRE(exported.find("; layer_height") != std::string::npos);
                REQUIRE(exported.find("; fill_density") != std::string::npos);
            }
            THEN("Infill is emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, infill_regex));
            }
            THEN("Perimeters are emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, perimeters_regex));
            }
            THEN("Skirt is emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, skirt_regex));
            }
            THEN("final Z height is ~20mm") {
                double final_z {0.0};
                auto reader {GCodeReader()};
                reader.apply_config(print->config);
                reader.parse(exported, [&final_z] (GCodeReader& self, const GCodeReader::GCodeLine& line)
                {
                    final_z = std::max(final_z, static_cast<double>(self.Z)); // record the highest Z point we reach
                });
                REQUIRE(final_z == Approx(20.15));
                std::cerr << exported << "\n";
            }
        }
        WHEN("output is executed with complete objects and two differently-sized meshes") {
            Slic3r::Model model;
            config->set("first_layer_extrusion_width", 0);
            config->set("support_material", false);
            config->set("raft_layers", 0);
            config->set("complete_objects", true);
            config->set("gcode_comments", true);
            config->set("between_objects_gcode", "; between-object-gcode");
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20, TestMesh::overhang}, model, config)};
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("Some text output is generated.") {
                REQUIRE(exported.size() > 0);
            }
            THEN("Infill is emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, infill_regex));
            }
            THEN("Perimeters are emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, perimeters_regex));
            }
            THEN("Skirt is emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, skirt_regex));
            }
            THEN("Between-object-gcode is emitted.") {
                REQUIRE(exported.find("; between-object-gcode") != std::string::npos);
            }
        }
        WHEN("the output is executed with support material") {
            Slic3r::Model model;
            config->set("first_layer_extrusion_width", 0);
            config->set("support_material", true);
            config->set("raft_layers", 3);
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("Some text output is generated.") {
                REQUIRE(exported.size() > 0);
            }
            THEN("Exported text contains extrusion statistics.") {
                REQUIRE(exported.find("; external perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; top solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; support material extrusion width") != std::string::npos);
                REQUIRE(exported.find("; first layer extrusion width") == std::string::npos);
            }
        }
        WHEN("the output is executed with a separate first layer extrusion width") {
            Slic3r::Model model;
            config->set("first_layer_extrusion_width", 0.5);
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("Some text output is generated.") {
                REQUIRE(exported.size() > 0);
            }
            THEN("Exported text contains extrusion statistics.") {
                REQUIRE(exported.find("; external perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; top solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; support material extrusion width") == std::string::npos);
                REQUIRE(exported.find("; first layer extrusion width") != std::string::npos);
            }
        }
        WHEN("Cooling is enabled and the fan is disabled.") {
            config->set("cooling", true);
            config->set("disable_fan_first_layers", 5);
            Slic3r::Model model;
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("GCode to disable fan is emitted."){
                REQUIRE(exported.find("M107") != std::string::npos);
            }
        }

        gcode.clear();
    }
}
<commit_msg>added tests to check for height reset and that one object is printed before another.<commit_after>#include <catch.hpp>

#include <regex>
#include "test_data.hpp"
#include "libslic3r.h"
#include "GCodeReader.hpp"

using namespace Slic3r::Test;
using namespace Slic3r;

std::regex perimeters_regex("G1 X[-0-9.]* Y[-0-9.]* E[-0-9.]* ; perimeter");
std::regex infill_regex("G1 X[-0-9.]* Y[-0-9.]* E[-0-9.]* ; infill");
std::regex skirt_regex("G1 X[-0-9.]* Y[-0-9.]* E[-0-9.]* ; skirt");

SCENARIO( "PrintGCode basic functionality") {
    GIVEN("A default configuration and a print test object") {
        auto config {Slic3r::Config::new_from_defaults()};
        auto gcode {std::stringstream("")};

        WHEN("the output is executed with no support material") {
            config->set("first_layer_extrusion_width", 0);
            config->set("gcode_comments", true);
            config->set("start_gcode", "");
            Slic3r::Model model;
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            print->process();
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("Some text output is generated.") {
                REQUIRE(exported.size() > 0);
            }
            THEN("Exported text contains slic3r version") {
                REQUIRE(exported.find(SLIC3R_VERSION) != std::string::npos);
            }
            THEN("Exported text contains git commit id") {
                REQUIRE(exported.find("; Git Commit") != std::string::npos);
                REQUIRE(exported.find(BUILD_COMMIT) != std::string::npos);
            }
            THEN("Exported text contains extrusion statistics.") {
                REQUIRE(exported.find("; external perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; top solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; support material extrusion width") == std::string::npos);
                REQUIRE(exported.find("; first layer extrusion width") == std::string::npos);
            }

            THEN("GCode preamble is emitted.") {
                REQUIRE(exported.find("G21 ; set units to millimeters") != std::string::npos);
            }

            THEN("Config options emitted for print config, default region config, default object config") {
                REQUIRE(exported.find("; first_layer_temperature") != std::string::npos);
                REQUIRE(exported.find("; layer_height") != std::string::npos);
                REQUIRE(exported.find("; fill_density") != std::string::npos);
            }
            THEN("Infill is emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, infill_regex));
            }
            THEN("Perimeters are emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, perimeters_regex));
            }
            THEN("Skirt is emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, skirt_regex));
            }
            THEN("final Z height is ~20mm") {
                double final_z {0.0};
                auto reader {GCodeReader()};
                reader.apply_config(print->config);
                reader.parse(exported, [&final_z] (GCodeReader& self, const GCodeReader::GCodeLine& line)
                {
                    final_z = std::max(final_z, static_cast<double>(self.Z)); // record the highest Z point we reach
                });
                REQUIRE(final_z == Approx(20.15));
            }
        }
        WHEN("output is executed with complete objects and two differently-sized meshes") {
            Slic3r::Model model;
            config->set("first_layer_extrusion_width", 0);
            config->set("first_layer_height", 0.3);
            config->set("support_material", false);
            config->set("raft_layers", 0);
            config->set("complete_objects", true);
            config->set("gcode_comments", true);
            config->set("between_objects_gcode", "; between-object-gcode");
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20, TestMesh::ipadstand}, model, config)};
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("Some text output is generated.") {
                REQUIRE(exported.size() > 0);
            }
            THEN("Infill is emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, infill_regex));
            }
            THEN("Perimeters are emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, perimeters_regex));
            }
            THEN("Skirt is emitted.") {
                std::smatch has_match;
                REQUIRE(std::regex_search(exported, has_match, skirt_regex));
            }
            THEN("Between-object-gcode is emitted.") {
                REQUIRE(exported.find("; between-object-gcode") != std::string::npos);
            }
            THEN("final Z height is ~27mm") {
                double final_z {0.0};
                auto reader {GCodeReader()};
                reader.apply_config(print->config);
                reader.parse(exported, [&final_z] (GCodeReader& self, const GCodeReader::GCodeLine& line)
                {
                    final_z = std::max(final_z, static_cast<double>(self.Z)); // record the highest Z point we reach
                });
                REQUIRE(final_z == Approx(30).margin(0.1)); // close enough
            }
            THEN("Z height resets on object change") {
                double final_z {0.0};
                bool reset {false};
                auto reader {GCodeReader()};
                reader.apply_config(print->config);
                reader.parse(exported, [&final_z, &reset] (GCodeReader& self, const GCodeReader::GCodeLine& line)
                {
                    if (final_z > 0 && std::abs(self.Z - 0.3) < 0.01 ) { // saw higher Z before this, now it's lower
                        reset = true;
                    } else {
                        final_z = std::max(final_z, static_cast<double>(self.Z)); // record the highest Z point we reach
                    }
                });
                REQUIRE(reset == true);
            }
            THEN("Shorter object is printed before taller object.") {
                double final_z {0.0};
                bool reset {false};
                auto reader {GCodeReader()};
                reader.apply_config(print->config);
                reader.parse(exported, [&final_z, &reset] (GCodeReader& self, const GCodeReader::GCodeLine& line)
                {
                    if (final_z > 0 && std::abs(self.Z - 0.3) < 0.01 ) {
                        reset = (final_z > 20.0);
                    } else {
                        final_z = std::max(final_z, static_cast<double>(self.Z)); // record the highest Z point we reach
                    }
                });
                REQUIRE(reset == true);
            }
        }
        WHEN("the output is executed with support material") {
            Slic3r::Model model;
            config->set("first_layer_extrusion_width", 0);
            config->set("support_material", true);
            config->set("raft_layers", 3);
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("Some text output is generated.") {
                REQUIRE(exported.size() > 0);
            }
            THEN("Exported text contains extrusion statistics.") {
                REQUIRE(exported.find("; external perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; top solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; support material extrusion width") != std::string::npos);
                REQUIRE(exported.find("; first layer extrusion width") == std::string::npos);
            }
        }
        WHEN("the output is executed with a separate first layer extrusion width") {
            Slic3r::Model model;
            config->set("first_layer_extrusion_width", 0.5);
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("Some text output is generated.") {
                REQUIRE(exported.size() > 0);
            }
            THEN("Exported text contains extrusion statistics.") {
                REQUIRE(exported.find("; external perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; perimeters extrusion width") != std::string::npos);
                REQUIRE(exported.find("; infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; top solid infill extrusion width") != std::string::npos);
                REQUIRE(exported.find("; support material extrusion width") == std::string::npos);
                REQUIRE(exported.find("; first layer extrusion width") != std::string::npos);
            }
        }
        WHEN("Cooling is enabled and the fan is disabled.") {
            config->set("cooling", true);
            config->set("disable_fan_first_layers", 5);
            Slic3r::Model model;
            auto print {Slic3r::Test::init_print({TestMesh::cube_20x20x20}, model, config)};
            Slic3r::Test::gcode(gcode, print);
            auto exported {gcode.str()};
            THEN("GCode to disable fan is emitted."){
                REQUIRE(exported.find("M107") != std::string::npos);
            }
        }

        gcode.clear();
    }
}
<|endoftext|>


<commit_before>/**
 * Performance test: logistic.
 *
 * This test runs a simple logistic model 100 times with a fixed
 * seed. The test records to a csv file information about the current
 * build, whether the values match the expected known values, whether
 * values are identical between runs, and the runtime in seconds for
 * each of the 100 individual runs.
 *
 * The output file is a csv file located at
 * test/performance/performance.csv.  If the file is empty, a header
 * line will be written.  If the file is not empty and the header line
 * of the file matches, a data row will be appended.  If the file is
 * not empty and the header line is different, a header row and a data
 * row will be appended.
 *
 * Below are the test routines in this test.
 * 1. run: Runs the model 100 times. This test should always
 *    succeed. Test failure indicates that the model could not be run.
 * 2. values_from_tagged_version: Compares the first run's final
 *    iteration against known values. Test will succeed if the values
 *    match the known values; the test will fail otherwise.
 * 3. values_same_run_to_run: Compares the first run's final iteration
 *    against all runs' final iterations. Test will succeed if all the
 *    values match; the test will fail otherwise.
 * 4. write_results_to_disk: Writes the results to disk. Test will
 *    succeed if writing to an empty file or to one with a matching
 *    header; the test will fail if the header in the existing file
 *    does not match the current header.
 *
 * Note: the values_from_tagged_version will need to be updated
 * if Stan's RNG changes, the seeding mechanism changes, or the
 * algorithm changes. The other routines should be fine.
 *
 * Each run of this test produces a single, csv row with 106 columns
 * in the output file:
 *   1. current date. Formatted using std::ctime: "Www Mmm dd hh:mm:ss yyyy"
 *   2. git hash. The current 40-character SHA-1 git hash or "NA".
 *   3. git date. The date of the last commit or "NA".
 *   4. model name. "logistic"
 *   5. matches tagged version. Either "yes" or "no".
 *   6. all values the same. Either "yes" or "no".
 *   7--106. run time (in seconds).
 */

#include <gtest/gtest.h>
#include <test/test-models/performance/logistic.hpp>
#include <stan/version.hpp>
#include <ctime>
#include <test/performance/utility.hpp>
#include <boost/algorithm/string/trim.hpp>

class performance : public ::testing::Test {
 public:
  static void SetUpTestCase() {
    N = 100;
    seconds_per_run.resize(N);
    last_draws_per_run.resize(N);
    matches_tagged_version = false;
    all_values_same = false;
  }

  static int N;
  static std::vector<double> seconds_per_run;
  static std::vector<std::vector<double> > last_draws_per_run;
  static bool matches_tagged_version;
  static bool all_values_same;
};

int performance::N;
std::vector<double> performance::seconds_per_run;
std::vector<std::vector<double> > performance::last_draws_per_run;
bool performance::matches_tagged_version;
bool performance::all_values_same;

using stan::test::performance::get_date;
using stan::test::performance::get_git_date;
using stan::test::performance::get_git_hash;
using stan::test::performance::get_last_iteration_from_file;
using stan::test::performance::quote;
using stan::test::performance::run_command;
using stan::test::performance::run_command_output;

TEST_F(performance, run) {
  clock_t t;
  for (int n = 0; n < N; ++n) {
    std::cout << "iteration: " << n << " / " << N << std::endl;
    t = clock();  // start timer
    stan::test::performance::command<stan_model>(
        1000, 10000, "src/test/test-models/performance/logistic.data.R",
        "test/performance/logistic_output.csv", 0U);
    t = clock() - t;  // end timer
    seconds_per_run[n] = static_cast<double>(t) / CLOCKS_PER_SEC;
    last_draws_per_run[n]
        = get_last_iteration_from_file("test/performance/logistic_output.csv");
  }
  SUCCEED();
}

// evaluate
TEST_F(performance, values_from_tagged_version) {
  int N_values = 9;
  ASSERT_EQ(N_values, last_draws_per_run[0].size())
      << "last tagged version, 2.17.0, had " << N_values << " elements";

  std::vector<double> first_run = last_draws_per_run[0];
  EXPECT_FLOAT_EQ(-66.0868, first_run[0]) << "lp__: index 0";

  EXPECT_FLOAT_EQ(0.958736, first_run[1]) << "accept_stat__: index 1";

  EXPECT_FLOAT_EQ(0.76969099, first_run[2]) << "stepsize__: index 2";

  EXPECT_FLOAT_EQ(2, first_run[3]) << "treedepth__: index 3";

  EXPECT_FLOAT_EQ(3, first_run[4]) << "n_leapfrog__: index 4";

  EXPECT_FLOAT_EQ(0, first_run[5]) << "divergent__: index 5";

  EXPECT_FLOAT_EQ(66.158401, first_run[6]) << "energy__: index 6";

  EXPECT_FLOAT_EQ(1.23053, first_run[7]) << "beta.1: index 7";

  EXPECT_FLOAT_EQ(-0.79178798, first_run[8]) << "beta.2: index 8";

  matches_tagged_version = !HasNonfatalFailure();
}

TEST_F(performance, values_same_run_to_run) {
  int N_values = last_draws_per_run[0].size();

  for (int i = 0; i < N_values; i++) {
    double expected_value = last_draws_per_run[0][i];
    for (int n = 1; n < N; n++) {
      EXPECT_FLOAT_EQ(expected_value, last_draws_per_run[n][i])
          << "expecting run to run values to be the same. Found run " << n
          << " to have different values than the 0th run for "
          << "index: " << i;
    }
  }
  all_values_same = !HasNonfatalFailure();
}

TEST_F(performance, check_output_is_same) {
  std::ifstream file_stream;
  file_stream.open("test/performance/logistic_output.csv", std::ios_base::in);
  ASSERT_TRUE(file_stream.good());

  std::string line, expected;

  getline(file_stream, line);
  ASSERT_EQ(
      "lp__,accept_stat__,stepsize__,treedepth__,n_leapfrog__,divergent__,"
      "energy__,beta.1,beta.2",
      line);
  ASSERT_TRUE(file_stream.good());

  getline(file_stream, line);
  ASSERT_EQ("# Adaptation terminated", line);
  ASSERT_TRUE(file_stream.good());

  file_stream.close();
}

TEST_F(performance, write_results_to_disk) {
  std::stringstream header;
  std::stringstream line;

  // current date / time
  header << quote("date");
  line << quote(get_date());

  // git hash
  header << "," << quote("git hash") << "," << quote("git date");
  line << "," << quote(get_git_hash()) << "," << quote(get_git_date());

  // model name: "logistic"
  header << "," << quote("model name");
  line << "," << quote("logistic");

  // matches tagged values
  header << "," << quote("matches tagged version");
  line << "," << quote(matches_tagged_version ? "yes" : "no");

  // all values same
  header << "," << quote("all values same");
  line << "," << quote(all_values_same ? "yes" : "no");

  // N times
  for (int n = 0; n < N; n++) {
    std::stringstream ss;
    ss << "run " << n + 1;
    header << "," << quote(ss.str());
    line << "," << seconds_per_run[n];
  }

  // append output to: test/performance/performance.csv
  bool write_header = false;
  std::fstream file_stream;

  file_stream.open("test/performance/performance.csv", std::ios_base::in);
  if (file_stream.peek() == std::fstream::traits_type::eof()) {
    write_header = true;
  } else {
    std::string file_header;
    std::getline(file_stream, file_header);

    EXPECT_EQ(file_header, header.str()) << "header of file is different";
    if (file_header != header.str())
      write_header = true;
  }
  file_stream.close();

  file_stream.open("test/performance/performance.csv", std::ios_base::app);
  if (write_header)
    file_stream << header.str() << std::endl;
  file_stream << line.str() << std::endl;
  file_stream.close();
}
<commit_msg>Update performance test<commit_after>/**
 * Performance test: logistic.
 *
 * This test runs a simple logistic model 100 times with a fixed
 * seed. The test records to a csv file information about the current
 * build, whether the values match the expected known values, whether
 * values are identical between runs, and the runtime in seconds for
 * each of the 100 individual runs.
 *
 * The output file is a csv file located at
 * test/performance/performance.csv.  If the file is empty, a header
 * line will be written.  If the file is not empty and the header line
 * of the file matches, a data row will be appended.  If the file is
 * not empty and the header line is different, a header row and a data
 * row will be appended.
 *
 * Below are the test routines in this test.
 * 1. run: Runs the model 100 times. This test should always
 *    succeed. Test failure indicates that the model could not be run.
 * 2. values_from_tagged_version: Compares the first run's final
 *    iteration against known values. Test will succeed if the values
 *    match the known values; the test will fail otherwise.
 * 3. values_same_run_to_run: Compares the first run's final iteration
 *    against all runs' final iterations. Test will succeed if all the
 *    values match; the test will fail otherwise.
 * 4. write_results_to_disk: Writes the results to disk. Test will
 *    succeed if writing to an empty file or to one with a matching
 *    header; the test will fail if the header in the existing file
 *    does not match the current header.
 *
 * Note: the values_from_tagged_version will need to be updated
 * if Stan's RNG changes, the seeding mechanism changes, or the
 * algorithm changes. The other routines should be fine.
 *
 * Each run of this test produces a single, csv row with 106 columns
 * in the output file:
 *   1. current date. Formatted using std::ctime: "Www Mmm dd hh:mm:ss yyyy"
 *   2. git hash. The current 40-character SHA-1 git hash or "NA".
 *   3. git date. The date of the last commit or "NA".
 *   4. model name. "logistic"
 *   5. matches tagged version. Either "yes" or "no".
 *   6. all values the same. Either "yes" or "no".
 *   7--106. run time (in seconds).
 */

#include <gtest/gtest.h>
#include <test/test-models/performance/logistic.hpp>
#include <stan/version.hpp>
#include <ctime>
#include <test/performance/utility.hpp>
#include <boost/algorithm/string/trim.hpp>

class performance : public ::testing::Test {
 public:
  static void SetUpTestCase() {
    N = 100;
    seconds_per_run.resize(N);
    last_draws_per_run.resize(N);
    matches_tagged_version = false;
    all_values_same = false;
  }

  static int N;
  static std::vector<double> seconds_per_run;
  static std::vector<std::vector<double> > last_draws_per_run;
  static bool matches_tagged_version;
  static bool all_values_same;
};

int performance::N;
std::vector<double> performance::seconds_per_run;
std::vector<std::vector<double> > performance::last_draws_per_run;
bool performance::matches_tagged_version;
bool performance::all_values_same;

using stan::test::performance::get_date;
using stan::test::performance::get_git_date;
using stan::test::performance::get_git_hash;
using stan::test::performance::get_last_iteration_from_file;
using stan::test::performance::quote;
using stan::test::performance::run_command;
using stan::test::performance::run_command_output;

TEST_F(performance, run) {
  clock_t t;
  for (int n = 0; n < N; ++n) {
    std::cout << "iteration: " << n << " / " << N << std::endl;
    t = clock();  // start timer
    stan::test::performance::command<stan_model>(
        1000, 10000, "src/test/test-models/performance/logistic.data.R",
        "test/performance/logistic_output.csv", 0U);
    t = clock() - t;  // end timer
    seconds_per_run[n] = static_cast<double>(t) / CLOCKS_PER_SEC;
    last_draws_per_run[n]
        = get_last_iteration_from_file("test/performance/logistic_output.csv");
  }
  SUCCEED();
}

// evaluate
TEST_F(performance, values_from_tagged_version) {
  int N_values = 9;
  ASSERT_EQ(N_values, last_draws_per_run[0].size())
      << "last tagged version, 2.17.0, had " << N_values << " elements";

  std::vector<double> first_run = last_draws_per_run[0];
  EXPECT_FLOAT_EQ(-66.992599, first_run[0]) << "lp__: index 0";

  EXPECT_FLOAT_EQ(0.97065002, first_run[1]) << "accept_stat__: index 1";

  EXPECT_FLOAT_EQ(0.77005202, first_run[2]) << "stepsize__: index 2";

  EXPECT_FLOAT_EQ(3, first_run[3]) << "treedepth__: index 3";

  EXPECT_FLOAT_EQ(7, first_run[4]) << "n_leapfrog__: index 4";

  EXPECT_FLOAT_EQ(0, first_run[5]) << "divergent__: index 5";

  EXPECT_FLOAT_EQ(67.834, first_run[6]) << "energy__: index 6";

  EXPECT_FLOAT_EQ(0.915712, first_run[7]) << "beta.1: index 7";

  EXPECT_FLOAT_EQ(-0.334984, first_run[8]) << "beta.2: index 8";

  matches_tagged_version = !HasNonfatalFailure();
}

TEST_F(performance, values_same_run_to_run) {
  int N_values = last_draws_per_run[0].size();

  for (int i = 0; i < N_values; i++) {
    double expected_value = last_draws_per_run[0][i];
    for (int n = 1; n < N; n++) {
      EXPECT_FLOAT_EQ(expected_value, last_draws_per_run[n][i])
          << "expecting run to run values to be the same. Found run " << n
          << " to have different values than the 0th run for "
          << "index: " << i;
    }
  }
  all_values_same = !HasNonfatalFailure();
}

TEST_F(performance, check_output_is_same) {
  std::ifstream file_stream;
  file_stream.open("test/performance/logistic_output.csv", std::ios_base::in);
  ASSERT_TRUE(file_stream.good());

  std::string line, expected;

  getline(file_stream, line);
  ASSERT_EQ(
      "lp__,accept_stat__,stepsize__,treedepth__,n_leapfrog__,divergent__,"
      "energy__,beta.1,beta.2",
      line);
  ASSERT_TRUE(file_stream.good());

  getline(file_stream, line);
  ASSERT_EQ("# Adaptation terminated", line);
  ASSERT_TRUE(file_stream.good());

  file_stream.close();
}

TEST_F(performance, write_results_to_disk) {
  std::stringstream header;
  std::stringstream line;

  // current date / time
  header << quote("date");
  line << quote(get_date());

  // git hash
  header << "," << quote("git hash") << "," << quote("git date");
  line << "," << quote(get_git_hash()) << "," << quote(get_git_date());

  // model name: "logistic"
  header << "," << quote("model name");
  line << "," << quote("logistic");

  // matches tagged values
  header << "," << quote("matches tagged version");
  line << "," << quote(matches_tagged_version ? "yes" : "no");

  // all values same
  header << "," << quote("all values same");
  line << "," << quote(all_values_same ? "yes" : "no");

  // N times
  for (int n = 0; n < N; n++) {
    std::stringstream ss;
    ss << "run " << n + 1;
    header << "," << quote(ss.str());
    line << "," << seconds_per_run[n];
  }

  // append output to: test/performance/performance.csv
  bool write_header = false;
  std::fstream file_stream;

  file_stream.open("test/performance/performance.csv", std::ios_base::in);
  if (file_stream.peek() == std::fstream::traits_type::eof()) {
    write_header = true;
  } else {
    std::string file_header;
    std::getline(file_stream, file_header);

    EXPECT_EQ(file_header, header.str()) << "header of file is different";
    if (file_header != header.str())
      write_header = true;
  }
  file_stream.close();

  file_stream.open("test/performance/performance.csv", std::ios_base::app);
  if (write_header)
    file_stream << header.str() << std::endl;
  file_stream << line.str() << std::endl;
  file_stream.close();
}
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <bitset>
#include <sstream>
#include <unistd.h>
#include <vector>
#include <algorithm>
#include <list>
#include <map>

#include "segment.h"
#include "message.h"
#include "loc_success_message.h"
#include "loc_failure_message.h"
#include "loc_request_message.h"
#include "execute_success_message.h"
#include "execute_failure_message.h"
#include "execute_request_message.h"
#include "register_success_message.h"
#include "register_failure_message.h"
#include "register_request_message.h"
#include "terminate_message.h"
#include "rpc.h"
#include "constants.h"
#include "network.h"
#include "helper_functions.h"

using namespace std;

// Global variables for client
bool connectedToBinder = false;
int binderSocket = 0;

// Global variables for server
static map<procedure_signature, skeleton, ps_compare> procSkeleDict;
string serverIdentifier;
unsigned int port = 0;
int welcomeSocket = 0;
bool onSwitch = true;

void mapPrint(){
  cout << "procSkeleDict size: "<<procSkeleDict.size() << endl;

  cout << "Map Print: ";

  for(map<procedure_signature, skeleton>::iterator it = procSkeleDict.begin();
   it != procSkeleDict.end(); ++it){

    cout << it->first.name << ", ";
  }

  cout << endl;
}

void printArgTypes(int * argTypes){
  cout << " Printing argTypes: " ;

  unsigned num = countNumOfArgTypes(argTypes);

  for(int i = 0; i < num; i++){
    cout << argTypes[i] << ", ";
  }
  cout << endl;
}

void printArgs(int * argTypes, void  ** args){
  cout << "Printing args: " ;

  // Parses the argument from the buffer
  unsigned numOfArgs = countNumOfArgTypes(argTypes) - 1;

  cout<<"Number of args: " << numOfArgs << endl;

  for (unsigned int i = 0; i < numOfArgs; i++) {
    int argType = argTypes[i];
    int argTypeInformation =
      (argType & ARG_TYPE_INFORMATION_MASK) >> ARG_TYPE_INFORMATION_SHIFT_AMOUNT;
    int argTypeArrayLength = argType & ARG_TYPE_ARRAY_LENGTH_MASK;
    argTypeArrayLength = (argTypeArrayLength == 0) ? 1: argTypeArrayLength;
    void *arg = args[i];

    switch (argTypeInformation) {
      case ARG_CHAR: {
        cout << "Printing ARG_CHAR: " << endl;
        char *argCharArray = (char *) arg;
        cout << argCharArray << endl;
        break;
      }

      case ARG_SHORT: {
        cout << "Printing ARG_SHORT: " << endl;
        short *argShortArray = (short *) arg;
        for (int j = 0; j < argTypeArrayLength; j++) {
          cout << argShortArray[i] << ", ";
        }
        cout << endl;
        break;
      }

      case ARG_INT: {
        cout << "Printing ARG_INT: " << endl;
        int *argIntArray = (int *) arg;
        for (int j = 0; j < argTypeArrayLength; j++) {
          cout << argIntArray[j] << ", ";
        }
        cout << endl;
        break;
      }

      case ARG_LONG: {
        cout << "Printing ARG_LONG: " << endl;
        long *argLongArray = (long *) arg;
        for (int j = 0; j < argTypeArrayLength; j++) {
          cout << argLongArray[j] << ",";
        }
        cout << endl;
        break;
      }

      case ARG_DOUBLE: {
        cout << "Printing ARG_DOUBLE: " << endl;
        double *argDoubleArray = (double *) arg;
        for (int j = 0; j < argTypeArrayLength; j++) {
          cout << argDoubleArray[j] << ", ";
        }
        cout << endl;
        break;
      }

      case ARG_FLOAT: {
        cout << "Printing ARG_FLOAT: " << endl;
        float *argFloatArray = (float *) arg;
        for (int j = 0; j < argTypeArrayLength; j++) {
          cout << argFloatArray[j] << ", ";
        }
        cout << endl;
        break;
      }
    }
  }
  cout << endl;
}

// See interface (header file).
int rpcInit(){
	cout << "Running rpcInit..." << endl;

	/*
   * Creates a connection socket to be used for accepting connections
	 * from clients
   */
	welcomeSocket = createSocket();
	setUpToListen(welcomeSocket);
	serverIdentifier = getHostAddress();
	port = getSocketPort(welcomeSocket);

  cout << "This servers welcomeSocket is: " << welcomeSocket << endl;

	// Opens a connection to the binderz
	binderSocket = createSocket();
	string binderAddress = getBinderAddress();
	unsigned int binderPort = getBinderPort();
	setUpToConnect(binderSocket, binderAddress, binderPort);
  connectedToBinder = true;

  cout << "This servers binderSocket is: " << binderSocket << endl;

  return 0;
}

// See interface (header file).
int rpcCall(char *name, int *argTypes, void **args) {
  cout << "Running rpcCall..." << endl;

	string serverAddress;
	unsigned int serverPort = 0;
	int status;

	if(!connectedToBinder){
    cout << "Connecting to binder..." << endl;
		binderSocket = createSocket();
		string binderAddress = getBinderAddress();
		unsigned int binderPort = getBinderPort();
		status = setUpToConnect(binderSocket, binderAddress, binderPort);
	  connectedToBinder = true;
    cout << "Connected to binder..." << endl;
	}
	//do something with returnVal

  LocRequestMessage messageToBinder = LocRequestMessage(string(name), argTypes);
  Segment segmentToBinder =
	  Segment(messageToBinder.getLength(), MSG_TYPE_LOC_REQUEST, &messageToBinder);
  int binder_status = segmentToBinder.send(binderSocket);
  cout << "LOC REQUEST message sent..." << endl;

	//maybe error check with binder_status
  //TODO: SEGMENT FAULT IF NOT IN THIS FOR LOOP
	/**Server stuff **/
	if(binder_status >= 0){

    Segment *parsedSegment = 0;
    int tempStatus = 0;
    tempStatus = Segment::receive(binderSocket, parsedSegment);

    Message *messageFromBinder = parsedSegment->getMessage();
		switch (parsedSegment->getType()) {
			case MSG_TYPE_LOC_SUCCESS: {
				cout << "LOC SUCCESS message received..." << endl;
        LocSuccessMessage *lsm =
				  dynamic_cast<LocSuccessMessage *>(messageFromBinder);
				serverAddress = lsm->getServerIdentifier();
				serverPort = lsm->getPort();
				cout << "serverAddress: " << serverAddress << endl;
        cout << "serverPort: " << serverPort << endl;
        break;
			}

			case MSG_TYPE_LOC_FAILURE: {
        cout << "LOC FAILURE message received..." << endl;
				return -1;
				break;
			}
		}
	}

  cout << "Connecting to server..." << endl;
  int serverSocket = createSocket();
	int status1 = setUpToConnect(serverSocket, serverAddress, serverPort);

  cout << "status1: " << status1 << endl;
  cout << "Server Socket: " << serverSocket << endl;
  cout << "Server Address: " << serverAddress << endl;
  cout << "Server Port: " << serverPort << endl;
  cout << "Connected to server..." << endl;

  ExecuteRequestMessage exeReqMsg = ExecuteRequestMessage(name, argTypes, args);
  Segment exeReqSeg = Segment(exeReqMsg.getLength(), MSG_TYPE_EXECUTE_REQUEST, &exeReqMsg);
  int status2 =  exeReqSeg.send(serverSocket);

  cout << "Status of exeRegMsg send: " << status2 << endl;

  int returnVal = 0;

  Segment * parsedSegmentEsm = 0;
  int status3 = 0;
  status3 = Segment::receive(serverSocket, parsedSegmentEsm);
  cout << "Flag 1" << endl;

  //instead we have

  cout << "Flag 2" << endl;

  switch (parsedSegmentEsm->getType()) {
    case MSG_TYPE_EXECUTE_SUCCESS: {
      cout << "EXECUTE SUCCESS message received..." << endl;

      Message * msg = parsedSegmentEsm->getMessage();
      ExecuteSuccessMessage * esm = dynamic_cast<ExecuteSuccessMessage*>(msg);

      // TODO FIX: name = esm->getName();
      //argTypes = esm->getArgTypes();
      void** newArgs = esm->getArgs();
      unsigned numOfArgs = countNumOfArgTypes(esm->getArgTypes()) - 1;

      for (unsigned int i = 0; i < numOfArgs; i++) {
        args[i] = newArgs[i];
      }

      break;
    }

    case MSG_TYPE_EXECUTE_FAILURE: {
      cout << "EXECUTE FAILURE message received..." << endl;

      Message * cast = parsedSegmentEsm->getMessage();
      ExecuteFailureMessage * efm = dynamic_cast<ExecuteFailureMessage*>(cast);
      returnVal = efm->getReasonCode();
      break;
    }
  }

  close(serverSocket);
  return returnVal;
}

  //TODO:
  // CREATE SERVER
  // CONNECT TO BINDER

int rpcRegister(char * name, int *argTypes, skeleton f){
  cout << "Running rpcRegister..." << endl;
  RegisterRequestMessage regReqMsg = RegisterRequestMessage(serverIdentifier, port, name, argTypes);

  /*
  cout << "rpcRegister name: " << name << endl;
  cout << "rpcRegister serverIdentifier: " << serverIdentifier << endl;
  cout << "rpcRegister port: " << port << endl;
  */

  /*
  We should get seg.send to give us some feed back maybe
  int status = regReqMsg->send(binderSocket);
  */

  Segment regReqSeg = Segment(regReqMsg.getLength(), MSG_TYPE_REGISTER_REQUEST, &regReqMsg);
  int status = regReqSeg.send(binderSocket);

  //cout << "rpcRegister Status: " << status << endl;

  if(status >= 0){
    //Success
    Segment *parsedSegment = 0;
    int result = 0;
    result = Segment::receive(binderSocket, parsedSegment);

    if(parsedSegment->getType() == MSG_TYPE_REGISTER_SUCCESS){

      cout << "MSG_TYPE_REGISTER_SUCCESS" << endl;

      Message * cast = parsedSegment->getMessage();
      //Error Checking maybe
      RegisterSuccessMessage * rsm = dynamic_cast<RegisterSuccessMessage*>(cast);

      //struct procedure_signature k(string(name), argTypes);
      struct procedure_signature k = procedure_signature(string(name), argTypes);

      procSkeleDict[k] = f;

      cout << "k: " << k.name << ", "<< f << endl;

    }else if(parsedSegment->getType() == MSG_TYPE_REGISTER_FAILURE){
      return 0;
    }

  }else if( status < 0){
    //Error
    return -99;
  }

  return 1;
}

// See interface (header file).
int rpcExecute(){
  cout << "Running rpcExecute..." << endl;
  fd_set allSockets;
  fd_set readSockets;

  /*
   * Clears all entries from the all sockets set and the read
   * sockets set
   */
  FD_ZERO(&allSockets);
  FD_ZERO(&readSockets);

  /*
   * Adds the welcome socket to the all sockets set and sets
   * it as the maximum socket so far
   */
  FD_SET(binderSocket, &allSockets);
  FD_SET(welcomeSocket, &allSockets);
  int maxSocket = welcomeSocket;

  while (onSwitch) {
    readSockets = allSockets;

    // Checks if some of the sockets are ready to be read from
    int result = select(maxSocket + 1, &readSockets, 0, 0, 0);
    if (result < 0) {
      continue;
    }

    for (int i = 0; i <= maxSocket; i++) {
      if (!FD_ISSET(i, &readSockets)) {
        continue;
      }

      if (i == welcomeSocket) {

        /*
         * Creates the connection socket when a connection is made
         * to the welcome socket
         */
        int connectionSocket = acceptConnection(i);
        if (connectionSocket < 0) {
          continue;
        }

        // Adds the connection socket to the all sockets set
        FD_SET(connectionSocket, &allSockets);

        /*
         * Sets the connection socket as the maximum socket so far
         * if necessary
         */
        if (connectionSocket > maxSocket) {
          maxSocket = connectionSocket;
        }

      } else {

        /*
         * Creates a segment to receive data from the client/binder and
         * reads into it from the connection socket
         */
        Segment *segment = 0;
        result = 0;
        result = Segment::receive(i, segment);
        if (result < 0) {
          /*
           * Closes the connection socket and removes it from the
           * all sockets set
           */
          cout << "Bad result, I'm closing, i is: "<< i << endl;
          destroySocket(i);
          FD_CLR(i, &allSockets);
          continue;
        }

        switch (segment->getType()) {
          case MSG_TYPE_EXECUTE_REQUEST: {
            Message * cast = segment->getMessage();
            ExecuteRequestMessage * erm = dynamic_cast<ExecuteRequestMessage*>(cast);

            procedure_signature * ps = new procedure_signature(erm->getName(), erm->getArgTypes());

            cout << "erm->getName(): " << erm->getName() << endl;
            printArgTypes(erm->getArgTypes());
            printArgs(erm->getArgTypes(), erm->getArgs());

            skeleton skel = procSkeleDict[*ps];

            if(skel == 0){
              cout << "Skel is null" << endl;
            }

            int result = skel(erm->getArgTypes(), erm->getArgs());

            cout << "Result: " << result << endl;
            printArgs(erm->getArgTypes(), erm->getArgs());

            if(result == 0 ){
              ExecuteSuccessMessage exeSuccessMsg = ExecuteSuccessMessage(erm->getName(), erm->getArgTypes(), erm->getArgs());
              Segment exeSuccessSeg = Segment(exeSuccessMsg.getLength(), MSG_TYPE_EXECUTE_SUCCESS, &exeSuccessMsg);
              int tstatus = exeSuccessSeg.send(i);
              cout << "ExecuteSuccessMessage status: " << tstatus << endl;

            }else{
              ExecuteFailureMessage exeFailMsg = ExecuteFailureMessage(result);
              Segment exeFailSeg = Segment(exeFailMsg.getLength(), MSG_TYPE_EXECUTE_FAILURE, &exeFailMsg);
              int tstatus = exeFailSeg.send(i);
            }

            break;
          }

          case MSG_TYPE_TERMINATE: {
            cout << "Got to terminate" << endl;
            if (i != binderSocket) {
               return ERROR_CODE_TERMINATE;
            }
            onSwitch = false;
            break;
          }
        }

      }
    }
  }

  // Destroys the welcome socket
  cout << "We are destorying the welcomeSocket: " << welcomeSocket << endl;
  destroySocket(welcomeSocket);

  return SUCCESS_CODE;
}

int rpcCacheCall() {
  cout << "Running rpcCacheCall..." << endl;
	return SUCCESS_CODE;
}

int rpcTerminate() {
	cout << "Running rpcTerminate..." << endl;

  // Sends a terminate message to the binder
  TerminateMessage messageToBinder = TerminateMessage();
  Segment segmentToBinder =
    Segment(messageToBinder.getLength(), MSG_TYPE_TERMINATE, &messageToBinder);
  int binder_status = segmentToBinder.send(binderSocket);
  cout << segmentToBinder.getType() << endl;

  cout << "binderSocket: " << binderSocket << endl;
  // Closes the connection to the binder
  destroySocket(binderSocket);

	return SUCCESS_CODE;
}
<commit_msg>changes<commit_after>#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <bitset>
#include <sstream>
#include <unistd.h>
#include <vector>
#include <algorithm>
#include <list>
#include <map>

#include "segment.h"
#include "message.h"
#include "loc_success_message.h"
#include "loc_failure_message.h"
#include "loc_request_message.h"
#include "execute_success_message.h"
#include "execute_failure_message.h"
#include "execute_request_message.h"
#include "register_success_message.h"
#include "register_failure_message.h"
#include "register_request_message.h"
#include "terminate_message.h"
#include "rpc.h"
#include "constants.h"
#include "network.h"
#include "helper_functions.h"

using namespace std;

// Global variables for client
bool connectedToBinder = false;
int binderSocket = 0;

// Global variables for server
static map<procedure_signature, skeleton, ps_compare> procSkeleDict;
string serverIdentifier;
unsigned int port = 0;
int welcomeSocket = 0;
bool onSwitch = true;

void mapPrint(){
  cout << "procSkeleDict size: "<<procSkeleDict.size() << endl;

  cout << "Map Print: ";

  for(map<procedure_signature, skeleton>::iterator it = procSkeleDict.begin();
   it != procSkeleDict.end(); ++it){

    cout << it->first.name << ", ";
  }

  cout << endl;
}

void printArgTypes(int * argTypes){
  cout << " Printing argTypes: " ;

  unsigned num = countNumOfArgTypes(argTypes);

  for(int i = 0; i < num; i++){
    cout << argTypes[i] << ", ";
  }
  cout << endl;
}

void printArgs(int * argTypes, void  ** args){
  cout << "Printing args: " ;

  // Parses the argument from the buffer
  unsigned numOfArgs = countNumOfArgTypes(argTypes) - 1;

  cout<<"Number of args: " << numOfArgs << endl;

  for (unsigned int i = 0; i < numOfArgs; i++) {
    int argType = argTypes[i];
    int argTypeInformation =
      (argType & ARG_TYPE_INFORMATION_MASK) >> ARG_TYPE_INFORMATION_SHIFT_AMOUNT;
    int argTypeArrayLength = argType & ARG_TYPE_ARRAY_LENGTH_MASK;
    argTypeArrayLength = (argTypeArrayLength == 0) ? 1: argTypeArrayLength;
    void *arg = args[i];

    switch (argTypeInformation) {
      case ARG_CHAR: {
        cout << "Printing ARG_CHAR: " << endl;
        char *argCharArray = (char *) arg;
        cout << argCharArray << endl;
        break;
      }

      case ARG_SHORT: {
        cout << "Printing ARG_SHORT: " << endl;
        short *argShortArray = (short *) arg;
        for (int j = 0; j < argTypeArrayLength; j++) {
          cout << argShortArray[i] << ", ";
        }
        cout << endl;
        break;
      }

      case ARG_INT: {
        cout << "Printing ARG_INT: " << endl;
        int *argIntArray = (int *) arg;
        for (int j = 0; j < argTypeArrayLength; j++) {
          cout << argIntArray[j] << ", ";
        }
        cout << endl;
        break;
      }

      case ARG_LONG: {
        cout << "Printing ARG_LONG: " << endl;
        long *argLongArray = (long *) arg;
        for (int j = 0; j < argTypeArrayLength; j++) {
          cout << argLongArray[j] << ",";
        }
        cout << endl;
        break;
      }

      case ARG_DOUBLE: {
        cout << "Printing ARG_DOUBLE: " << endl;
        double *argDoubleArray = (double *) arg;
        for (int j = 0; j < argTypeArrayLength; j++) {
          cout << argDoubleArray[j] << ", ";
        }
        cout << endl;
        break;
      }

      case ARG_FLOAT: {
        cout << "Printing ARG_FLOAT: " << endl;
        float *argFloatArray = (float *) arg;
        for (int j = 0; j < argTypeArrayLength; j++) {
          cout << argFloatArray[j] << ", ";
        }
        cout << endl;
        break;
      }
    }
  }
  cout << endl;
}

// See interface (header file).
int rpcInit(){
	cout << "Running rpcInit..." << endl;

	/*
   * Creates a connection socket to be used for accepting connections
	 * from clients
   */
	welcomeSocket = createSocket();
	setUpToListen(welcomeSocket);
	serverIdentifier = getHostAddress();
	port = getSocketPort(welcomeSocket);

  cout << "This servers welcomeSocket is: " << welcomeSocket << endl;

	// Opens a connection to the binderz
	binderSocket = createSocket();
	string binderAddress = getBinderAddress();
	unsigned int binderPort = getBinderPort();
	setUpToConnect(binderSocket, binderAddress, binderPort);
  connectedToBinder = true;

  cout << "This servers binderSocket is: " << binderSocket << endl;

  return 0;
}

// See interface (header file).
int rpcCall(char *name, int *argTypes, void **args) {
  cout << "Running rpcCall..." << endl;

	string serverAddress;
	unsigned int serverPort = 0;
	int status;

	if(!connectedToBinder){
    cout << "Connecting to binder..." << endl;
		binderSocket = createSocket();
		string binderAddress = getBinderAddress();
		unsigned int binderPort = getBinderPort();
		status = setUpToConnect(binderSocket, binderAddress, binderPort);
	  connectedToBinder = true;
    cout << "Connected to binder..." << endl;
	}
	//do something with returnVal

  LocRequestMessage messageToBinder = LocRequestMessage(string(name), argTypes);
  Segment segmentToBinder =
	  Segment(messageToBinder.getLength(), MSG_TYPE_LOC_REQUEST, &messageToBinder);
  int binder_status = segmentToBinder.send(binderSocket);
  cout << "LOC REQUEST message sent..." << endl;

	//maybe error check with binder_status
  //TODO: SEGMENT FAULT IF NOT IN THIS FOR LOOP
	/**Server stuff **/
	if(binder_status >= 0){

    Segment *parsedSegment = 0;
    int tempStatus = 0;
    tempStatus = Segment::receive(binderSocket, parsedSegment);

    Message *messageFromBinder = parsedSegment->getMessage();
		switch (parsedSegment->getType()) {
			case MSG_TYPE_LOC_SUCCESS: {
				cout << "LOC SUCCESS message received..." << endl;
        LocSuccessMessage *lsm =
				  dynamic_cast<LocSuccessMessage *>(messageFromBinder);
				serverAddress = lsm->getServerIdentifier();
				serverPort = lsm->getPort();
				cout << "serverAddress: " << serverAddress << endl;
        cout << "serverPort: " << serverPort << endl;
        break;
			}

			case MSG_TYPE_LOC_FAILURE: {
        cout << "LOC FAILURE message received..." << endl;
				return -1;
				break;
			}
		}
	}

  cout << "Connecting to server..." << endl;
  int serverSocket = createSocket();
	int status1 = setUpToConnect(serverSocket, serverAddress, serverPort);

  cout << "status1: " << status1 << endl;
  cout << "Server Socket: " << serverSocket << endl;
  cout << "Server Address: " << serverAddress << endl;
  cout << "Server Port: " << serverPort << endl;
  cout << "Connected to server..." << endl;

  ExecuteRequestMessage exeReqMsg = ExecuteRequestMessage(name, argTypes, args);
  Segment exeReqSeg = Segment(exeReqMsg.getLength(), MSG_TYPE_EXECUTE_REQUEST, &exeReqMsg);
  int status2 =  exeReqSeg.send(serverSocket);

  cout << "Status of exeRegMsg send: " << status2 << endl;

  int returnVal = 0;

  Segment * parsedSegmentEsm = 0;
  int status3 = 0;
  status3 = Segment::receive(serverSocket, parsedSegmentEsm);
  cout << "Flag 1" << endl;

  //instead we have

  cout << "Flag 2" << endl;

  switch (parsedSegmentEsm->getType()) {
    case MSG_TYPE_EXECUTE_SUCCESS: {
      cout << "EXECUTE SUCCESS message received..." << endl;

      Message * msg = parsedSegmentEsm->getMessage();
      ExecuteSuccessMessage * esm = dynamic_cast<ExecuteSuccessMessage*>(msg);

      // TODO FIX: name = esm->getName();
      //argTypes = esm->getArgTypes();
      void** newArgs = esm->getArgs();
      unsigned numOfArgs = countNumOfArgTypes(esm->getArgTypes()) - 1;

      for (unsigned int i = 0; i < numOfArgs; i++) {
        args[i] = newArgs[i];
      }

      break;
    }

    case MSG_TYPE_EXECUTE_FAILURE: {
      cout << "EXECUTE FAILURE message received..." << endl;

      Message * cast = parsedSegmentEsm->getMessage();
      ExecuteFailureMessage * efm = dynamic_cast<ExecuteFailureMessage*>(cast);
      returnVal = efm->getReasonCode();
      break;
    }
  }

  close(serverSocket);
  return returnVal;
}

  //TODO:
  // CREATE SERVER
  // CONNECT TO BINDER

int rpcRegister(char * name, int *argTypes, skeleton f){
  cout << "Running rpcRegister..." << endl;
  RegisterRequestMessage regReqMsg = RegisterRequestMessage(serverIdentifier, port, name, argTypes);

  /*
  cout << "rpcRegister name: " << name << endl;
  cout << "rpcRegister serverIdentifier: " << serverIdentifier << endl;
  cout << "rpcRegister port: " << port << endl;
  */

  /*
  We should get seg.send to give us some feed back maybe
  int status = regReqMsg->send(binderSocket);
  */

  Segment regReqSeg = Segment(regReqMsg.getLength(), MSG_TYPE_REGISTER_REQUEST, &regReqMsg);
  int status = regReqSeg.send(binderSocket);

  cout << "When we register we use this binderSocket: " << binderSocket;
  //cout << "rpcRegister Status: " << status << endl;

  if(status >= 0){
    //Success
    Segment *parsedSegment = 0;
    int result = 0;
    result = Segment::receive(binderSocket, parsedSegment);

    if(parsedSegment->getType() == MSG_TYPE_REGISTER_SUCCESS){

      cout << "MSG_TYPE_REGISTER_SUCCESS" << endl;

      Message * cast = parsedSegment->getMessage();
      //Error Checking maybe
      RegisterSuccessMessage * rsm = dynamic_cast<RegisterSuccessMessage*>(cast);

      //struct procedure_signature k(string(name), argTypes);
      struct procedure_signature k = procedure_signature(string(name), argTypes);

      procSkeleDict[k] = f;

      cout << "k: " << k.name << ", "<< f << endl;

    }else if(parsedSegment->getType() == MSG_TYPE_REGISTER_FAILURE){
      return 0;
    }

  }else if( status < 0){
    //Error
    return -99;
  }

  return 1;
}

// See interface (header file).
int rpcExecute(){
  cout << "Running rpcExecute..." << endl;
  fd_set allSockets;
  fd_set readSockets;

  /*
   * Clears all entries from the all sockets set and the read
   * sockets set
   */
  FD_ZERO(&allSockets);
  FD_ZERO(&readSockets);

  /*
   * Adds the welcome socket to the all sockets set and sets
   * it as the maximum socket so far
   */
  FD_SET(binderSocket, &allSockets);
  FD_SET(welcomeSocket, &allSockets);
  int maxSocket = welcomeSocket;

  while (onSwitch) {
    readSockets = allSockets;

    // Checks if some of the sockets are ready to be read from
    int result = select(maxSocket + 1, &readSockets, 0, 0, 0);
    if (result < 0) {
      continue;
    }

    for (int i = 0; i <= maxSocket; i++) {
      if (!FD_ISSET(i, &readSockets)) {
        continue;
      }

      if (i == welcomeSocket) {

        /*
         * Creates the connection socket when a connection is made
         * to the welcome socket
         */
        int connectionSocket = acceptConnection(i);
        if (connectionSocket < 0) {
          continue;
        }

        // Adds the connection socket to the all sockets set
        FD_SET(connectionSocket, &allSockets);

        /*
         * Sets the connection socket as the maximum socket so far
         * if necessary
         */
        if (connectionSocket > maxSocket) {
          maxSocket = connectionSocket;
        }

      } else {

        /*
         * Creates a segment to receive data from the client/binder and
         * reads into it from the connection socket
         */
        Segment *segment = 0;
        result = 0;
        result = Segment::receive(i, segment);
        if (result < 0) {
          /*
           * Closes the connection socket and removes it from the
           * all sockets set
           */
          cout << "Bad result, I'm closing, i is: "<< i << endl;
          destroySocket(i);
          FD_CLR(i, &allSockets);
          continue;
        }

        switch (segment->getType()) {
          case MSG_TYPE_EXECUTE_REQUEST: {
            Message * cast = segment->getMessage();
            ExecuteRequestMessage * erm = dynamic_cast<ExecuteRequestMessage*>(cast);

            procedure_signature * ps = new procedure_signature(erm->getName(), erm->getArgTypes());

            cout << "erm->getName(): " << erm->getName() << endl;
            printArgTypes(erm->getArgTypes());
            printArgs(erm->getArgTypes(), erm->getArgs());

            skeleton skel = procSkeleDict[*ps];

            if(skel == 0){
              cout << "Skel is null" << endl;
            }

            int result = skel(erm->getArgTypes(), erm->getArgs());

            cout << "Result: " << result << endl;
            printArgs(erm->getArgTypes(), erm->getArgs());

            if(result == 0 ){
              ExecuteSuccessMessage exeSuccessMsg = ExecuteSuccessMessage(erm->getName(), erm->getArgTypes(), erm->getArgs());
              Segment exeSuccessSeg = Segment(exeSuccessMsg.getLength(), MSG_TYPE_EXECUTE_SUCCESS, &exeSuccessMsg);
              int tstatus = exeSuccessSeg.send(i);
              cout << "ExecuteSuccessMessage status: " << tstatus << endl;

            }else{
              ExecuteFailureMessage exeFailMsg = ExecuteFailureMessage(result);
              Segment exeFailSeg = Segment(exeFailMsg.getLength(), MSG_TYPE_EXECUTE_FAILURE, &exeFailMsg);
              int tstatus = exeFailSeg.send(i);
            }

            break;
          }

          case MSG_TYPE_TERMINATE: {
            cout << "Got to terminate" << endl;
            if (i != binderSocket) {
               return ERROR_CODE_TERMINATE;
            }
            onSwitch = false;
            break;
          }
        }

      }
    }
  }

  // Destroys the welcome socket
  cout << "We are destorying the welcomeSocket: " << welcomeSocket << endl;
  destroySocket(welcomeSocket);

  return SUCCESS_CODE;
}

int rpcCacheCall() {
  cout << "Running rpcCacheCall..." << endl;
	return SUCCESS_CODE;
}

int rpcTerminate() {
	cout << "Running rpcTerminate..." << endl;

  // Sends a terminate message to the binder
  TerminateMessage messageToBinder = TerminateMessage();
  Segment segmentToBinder =
    Segment(messageToBinder.getLength(), MSG_TYPE_TERMINATE, &messageToBinder);
  int binder_status = segmentToBinder.send(binderSocket);
  cout << segmentToBinder.getType() << endl;

  cout << "binderSocket: " << binderSocket << endl;
  // Closes the connection to the binder
  destroySocket(binderSocket);

	return SUCCESS_CODE;
}
<|endoftext|>


<commit_before>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnordmetric/environment.h>
#include <fnordmetric/adminui.h>
#include <fnord/base/uri.h>

namespace fnordmetric {

std::unique_ptr<http::HTTPHandler> AdminUI::getHandler() {
  return std::unique_ptr<http::HTTPHandler>(new AdminUI());
}

AdminUI::AdminUI() :
    webui_bundle_("FnordMetric"),
    webui_mount_(&webui_bundle_, "/admin") {
  webui_bundle_.addComponent("fnord/3rdparty/codemirror.js");

  webui_bundle_.addComponent("fnord/3rdparty/fontawesome.woff");
  webui_bundle_.addComponent("fnord/3rdparty/fontawesome.css");
  webui_bundle_.addComponent("fnord/3rdparty/reset.css");
  webui_bundle_.addComponent("fnord/components/fn-table.css");
  webui_bundle_.addComponent("fnord/components/fn-button.css");
  webui_bundle_.addComponent("fnord/themes/midnight-blue.css");

  webui_bundle_.addComponent("fnord/fnord.js");
  webui_bundle_.addComponent("fnord/components/fn-appbar.html");
  webui_bundle_.addComponent("fnord/components/fn-button.html");
  webui_bundle_.addComponent("fnord/components/fn-button-group.html");
  webui_bundle_.addComponent("fnord/components/fn-icon.html");
  webui_bundle_.addComponent("fnord/components/fn-input.html");
  webui_bundle_.addComponent("fnord/components/fn-loader.html");
  webui_bundle_.addComponent("fnord/components/fn-menu.html");
  webui_bundle_.addComponent("fnord/components/fn-search.html");
  webui_bundle_.addComponent("fnord/components/fn-table.html");
  webui_bundle_.addComponent("fnord/components/fn-splitpane.html");
  webui_bundle_.addComponent("fnord/components/fn-codeeditor.html");
  webui_bundle_.addComponent("fnord/components/fn-dropdown.html");
  webui_bundle_.addComponent("fnord/components/fn-datepicker.html");
  webui_bundle_.addComponent("fnord/components/fn-timeinput.html");
  webui_bundle_.addComponent("fnord/components/fn-daterangepicker.html");
  webui_bundle_.addComponent("fnord/components/fn-tabbar.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-app.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-console.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-metric-list.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-search.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-query-editor.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-metric-preview.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-controls.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-time-controls.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-webui.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-webui.css");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-webui-util.js");
  webui_bundle_.addComponent(
    "fnordmetric/fnordmetric-embed-query-popup.html");
  webui_bundle_.addComponent(
      "fnordmetric-plugins/hosts/fnordmetric-plugin-hosts.html");

}

bool AdminUI::handleHTTPRequest(
    http::HTTPRequest* request,
    http::HTTPResponse* response) {

  if (env()->verbose()) {
    fnord::util::LogEntry log_entry;
    log_entry.append("__severity__", "DEBUG");
    log_entry.printf(
        "__message__",
        "HTTP request: %s %s",
        request->getMethod().c_str(),
        request->getUrl().c_str());

    env()->logger()->log(log_entry);
  }

  if (webui_mount_.handleHTTPRequest(request, response)) {
    return true;
  }

  fnord::URI uri(request->getUrl());
  auto path = uri.path();

  if (path == "/") {
    response->setStatus(http::kStatusFound);
    response->addHeader("Content-Type", "text/html; charset=utf-8");
    response->addHeader("Location", "/admin");
    return true;
  }

  return false;
}

}
<commit_msg>added templates to query popup<commit_after>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <fnordmetric/environment.h>
#include <fnordmetric/adminui.h>
#include <fnord/base/uri.h>

namespace fnordmetric {

std::unique_ptr<http::HTTPHandler> AdminUI::getHandler() {
  return std::unique_ptr<http::HTTPHandler>(new AdminUI());
}

AdminUI::AdminUI() :
    webui_bundle_("FnordMetric"),
    webui_mount_(&webui_bundle_, "/admin") {
  webui_bundle_.addComponent("fnord/3rdparty/codemirror.js");

  webui_bundle_.addComponent("fnord/3rdparty/fontawesome.woff");
  webui_bundle_.addComponent("fnord/3rdparty/fontawesome.css");
  webui_bundle_.addComponent("fnord/3rdparty/reset.css");
  webui_bundle_.addComponent("fnord/components/fn-table.css");
  webui_bundle_.addComponent("fnord/components/fn-button.css");
  webui_bundle_.addComponent("fnord/components/fn-modal.css");
  webui_bundle_.addComponent("fnord/components/fn-tabbar.css");
  webui_bundle_.addComponent("fnord/themes/midnight-blue.css");

  webui_bundle_.addComponent("fnord/fnord.js");
  webui_bundle_.addComponent("fnord/components/fn-appbar.html");
  webui_bundle_.addComponent("fnord/components/fn-button.html");
  webui_bundle_.addComponent("fnord/components/fn-button-group.html");
  webui_bundle_.addComponent("fnord/components/fn-icon.html");
  webui_bundle_.addComponent("fnord/components/fn-input.html");
  webui_bundle_.addComponent("fnord/components/fn-loader.html");
  webui_bundle_.addComponent("fnord/components/fn-menu.html");
  webui_bundle_.addComponent("fnord/components/fn-search.html");
  webui_bundle_.addComponent("fnord/components/fn-table.html");
  webui_bundle_.addComponent("fnord/components/fn-splitpane.html");
  webui_bundle_.addComponent("fnord/components/fn-codeeditor.html");
  webui_bundle_.addComponent("fnord/components/fn-dropdown.html");
  webui_bundle_.addComponent("fnord/components/fn-datepicker.html");
  webui_bundle_.addComponent("fnord/components/fn-timeinput.html");
  webui_bundle_.addComponent("fnord/components/fn-daterangepicker.html");
  webui_bundle_.addComponent("fnord/components/fn-tabbar.html");
  webui_bundle_.addComponent("fnord/components/fn-modal.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-app.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-console.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-metric-list.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-search.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-query-editor.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-metric-preview.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-controls.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-time-controls.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-webui.html");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-webui.css");
  webui_bundle_.addComponent("fnordmetric/fnordmetric-webui-util.js");
  webui_bundle_.addComponent(
    "fnordmetric/fnordmetric-embed-query-popup.html");
  webui_bundle_.addComponent(
      "fnordmetric-plugins/hosts/fnordmetric-plugin-hosts.html");

}

bool AdminUI::handleHTTPRequest(
    http::HTTPRequest* request,
    http::HTTPResponse* response) {

  if (env()->verbose()) {
    fnord::util::LogEntry log_entry;
    log_entry.append("__severity__", "DEBUG");
    log_entry.printf(
        "__message__",
        "HTTP request: %s %s",
        request->getMethod().c_str(),
        request->getUrl().c_str());

    env()->logger()->log(log_entry);
  }

  if (webui_mount_.handleHTTPRequest(request, response)) {
    return true;
  }

  fnord::URI uri(request->getUrl());
  auto path = uri.path();

  if (path == "/") {
    response->setStatus(http::kStatusFound);
    response->addHeader("Content-Type", "text/html; charset=utf-8");
    response->addHeader("Location", "/admin");
    return true;
  }

  return false;
}

}
<|endoftext|>


<commit_before>/*
 * Copyright 2018 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include <cstddef>
#include <cstring>
#include <type_traits>

#include "GrClip.h"
#include "GrContext.h"
#include "GrContextPriv.h"
#include "GrRenderTargetContext.h"
#include "GrTexture.h"
#include "SkImage_Gpu.h"
#include "SkImage_GpuYUVA.h"
#include "effects/GrYUVtoRGBEffect.h"

SkImage_GpuYUVA::SkImage_GpuYUVA(sk_sp<GrContext> context, int width, int height, uint32_t uniqueID,
                                 SkYUVColorSpace colorSpace, sk_sp<GrTextureProxy> proxies[],
                                 const SkYUVAIndex yuvaIndices[4],  GrSurfaceOrigin origin,
                                 sk_sp<SkColorSpace> imageColorSpace, SkBudgeted budgeted)
        : INHERITED(std::move(context), width, height, uniqueID,
                    // If an alpha channel is present we always switch to kPremul. This is because,
                    // although the planar data is always un-premul, the final interleaved RGB image
                    // is/would-be premul.
                    -1 != yuvaIndices[SkYUVAIndex::kA_Index].fIndex ? kPremul_SkAlphaType
                                                                    : kOpaque_SkAlphaType,
                    budgeted, imageColorSpace)
        , fYUVColorSpace(colorSpace)
        , fOrigin(origin) {
    int maxIndex = yuvaIndices[0].fIndex;
    for (int i = 1; i < 4; ++i) {
        if (yuvaIndices[i].fIndex > maxIndex) {
            maxIndex = yuvaIndices[i].fIndex;
        }
    }
    for (int i = 0; i <= maxIndex; ++i) {
        fProxies[i] = std::move(proxies[i]);
    }
    memcpy(fYUVAIndices, yuvaIndices, 4*sizeof(SkYUVAIndex));
}

SkImage_GpuYUVA::~SkImage_GpuYUVA() {}

SkImageInfo SkImage_GpuYUVA::onImageInfo() const {
    // Note: this is the imageInfo for the flattened image, not the YUV planes
    return SkImageInfo::Make(this->width(), this->height(), kRGBA_8888_SkColorType,
                             fAlphaType, fColorSpace);
}

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

sk_sp<GrTextureProxy> SkImage_GpuYUVA::asTextureProxyRef() const {
    if (!fRGBProxy) {
        sk_sp<GrTextureProxy> yProxy = fProxies[fYUVAIndices[SkYUVAIndex::kY_Index].fIndex];
        sk_sp<GrTextureProxy> uProxy = fProxies[fYUVAIndices[SkYUVAIndex::kU_Index].fIndex];
        sk_sp<GrTextureProxy> vProxy = fProxies[fYUVAIndices[SkYUVAIndex::kV_Index].fIndex];

        if (!yProxy || !uProxy || !vProxy) {
            return nullptr;
        }

        GrPaint paint;
        paint.setPorterDuffXPFactory(SkBlendMode::kSrc);

        // TODO: modify the YUVtoRGBEffect to do premul if fImageAlphaType is kPremul_AlphaType
        paint.addColorFragmentProcessor(GrYUVtoRGBEffect::Make(fProxies, fYUVAIndices,
                                                               fYUVColorSpace));

        const SkRect rect = SkRect::MakeIWH(this->width(), this->height());

        // Needs to create a render target in order to draw to it for the yuv->rgb conversion.
        sk_sp<GrRenderTargetContext> renderTargetContext(
            fContext->contextPriv().makeDeferredRenderTargetContext(
                SkBackingFit::kExact, this->width(), this->height(), kRGBA_8888_GrPixelConfig,
                std::move(fColorSpace), 1, GrMipMapped::kNo, fOrigin));
        if (!renderTargetContext) {
            return nullptr;
        }
        renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);

        if (!renderTargetContext->asSurfaceProxy()) {
            return nullptr;
        }

        // DDL TODO: in the promise image version we must not flush here
        fContext->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy());

        fRGBProxy = renderTargetContext->asTextureProxyRef();
    }

    return fRGBProxy;
}

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

//*** bundle this into a helper function used by this and SkImage_Gpu?
sk_sp<SkImage> SkImage_GpuYUVA::MakeFromYUVATextures(GrContext* ctx,
                                                     SkYUVColorSpace colorSpace,
                                                     const GrBackendTexture yuvaTextures[],
                                                     const SkYUVAIndex yuvaIndices[4],
                                                     int width,
                                                     int height,
                                                     GrSurfaceOrigin origin,
                                                     sk_sp<SkColorSpace> imageColorSpace) {
    GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();

    // Right now this still only deals with YUV and NV12 formats. Assuming that YUV has different
    // textures for U and V planes, while NV12 uses same texture for U and V planes.
    bool nv12 = (yuvaIndices[SkYUVAIndex::kU_Index].fIndex ==
                 yuvaIndices[SkYUVAIndex::kV_Index].fIndex);

    // We need to make a copy of the input backend textures because we need to preserve the result
    // of validate_backend_texture.
    GrBackendTexture yuvaTexturesCopy[4];
    for (int i = 0; i < 4; ++i) {
        // Validate that the yuvaIndices refer to valid backend textures.
        const SkYUVAIndex& yuvaIndex = yuvaIndices[i];
        if (SkYUVAIndex::kA_Index == i && yuvaIndex.fIndex == -1) {
            // Meaning the A plane isn't passed in.
            continue;
        }
        if (yuvaIndex.fIndex == -1 || yuvaIndex.fIndex > 3) {
            // Y plane, U plane, and V plane must refer to image sources being passed in. There are
            // at most 4 image sources being passed in, could not have a index more than 3.
            return nullptr;
        }
        SkColorType ct = kUnknown_SkColorType;
        if (SkYUVAIndex::kY_Index == i || SkYUVAIndex::kA_Index == i) {
            // The Y and A planes are always kAlpha8 (for now)
            ct = kAlpha_8_SkColorType;
        } else {
            // The UV planes can either be interleaved or planar
            ct = nv12 ? kRGBA_8888_SkColorType : kAlpha_8_SkColorType;
        }

        if (!yuvaTexturesCopy[yuvaIndex.fIndex].isValid()) {
            yuvaTexturesCopy[yuvaIndex.fIndex] = yuvaTextures[yuvaIndex.fIndex];
            // TODO: Instead of using assumption about whether it is NV12 format to guess colorType,
            // actually use channel information here.
            if (!ValidateBackendTexture(ctx, yuvaTexturesCopy[yuvaIndex.fIndex],
                                        &yuvaTexturesCopy[yuvaIndex.fIndex].fConfig,
                                        ct, kUnpremul_SkAlphaType, nullptr)) {
                return nullptr;
            }
        }

        // TODO: Check that for each plane, the channel actually exist in the image source we are
        // reading from.
    }

    sk_sp<GrTextureProxy> tempTextureProxies[4]; // build from yuvaTextures
    for (int i = 0; i < 4; ++i) {
        // Fill in tempTextureProxies to avoid duplicate texture proxies.
        int textureIndex = yuvaIndices[i].fIndex;

        // Safely ignore since this means we are missing the A plane.
        if (textureIndex == -1) {
            SkASSERT(SkYUVAIndex::kA_Index == i);
            continue;
        }

        if (!tempTextureProxies[textureIndex]) {
            SkASSERT(yuvaTexturesCopy[textureIndex].isValid());
            tempTextureProxies[textureIndex] =
                proxyProvider->wrapBackendTexture(yuvaTexturesCopy[textureIndex], origin);
            if (!tempTextureProxies[textureIndex]) {
                return nullptr;
            }
        }
    }

    return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(ctx), width, height, kNeedNewImageUniqueID,
                                       colorSpace, tempTextureProxies, yuvaIndices, origin,
                                       imageColorSpace, SkBudgeted::kYes);
}

/////////////////////////////////////////////////////////////////////////////////////////////////
sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(GrContext* context,
                                                       SkYUVColorSpace yuvColorSpace,
                                                       const GrBackendFormat yuvaFormats[],
                                                       const SkISize yuvaSizes[],
                                                       const SkYUVAIndex yuvaIndices[4],
                                                       int imageWidth,
                                                       int imageHeight,
                                                       GrSurfaceOrigin imageOrigin,
                                                       sk_sp<SkColorSpace> imageColorSpace,
                                                       TextureFulfillProc textureFulfillProc,
                                                       TextureReleaseProc textureReleaseProc,
                                                       PromiseDoneProc promiseDoneProc,
                                                       TextureContext textureContexts[]) {
    // The contract here is that if 'promiseDoneProc' is passed in it should always be called,
    // even if creation of the SkImage fails.
    if (!promiseDoneProc) {
        return nullptr;
    }

    int numTextures;
    bool valid = SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures);

    // Set up promise helpers
    SkPromiseImageHelper promiseHelpers[4];
    for (int texIdx = 0; texIdx < numTextures; ++texIdx) {
        promiseHelpers[texIdx].set(textureFulfillProc, textureReleaseProc, promiseDoneProc,
                                   textureContexts[texIdx]);
    }

    if (!valid) {
        return nullptr;
    }

    if (!context) {
        return nullptr;
    }

    if (imageWidth <= 0 || imageWidth <= 0) {
        return nullptr;
    }

    if (!textureFulfillProc || !textureReleaseProc) {
        return nullptr;
    }

    SkAlphaType at = (-1 != yuvaIndices[SkYUVAIndex::kA_Index].fIndex) ? kPremul_SkAlphaType
                                                                       : kOpaque_SkAlphaType;
    SkImageInfo info = SkImageInfo::Make(imageWidth, imageHeight, kRGBA_8888_SkColorType,
                                         at, imageColorSpace);
    if (!SkImageInfoIsValid(info)) {
        return nullptr;
    }

    // Set up color types
    SkColorType texColorTypes[4] = { kUnknown_SkColorType, kUnknown_SkColorType,
                                     kUnknown_SkColorType, kUnknown_SkColorType };
    for (int yuvIndex = 0; yuvIndex < 4; ++yuvIndex) {
        int texIdx = yuvaIndices[yuvIndex].fIndex;
        if (texIdx < 0) {
            SkASSERT(SkYUVAIndex::kA_Index);
            continue;
        }
        if (kUnknown_SkColorType == texColorTypes[texIdx]) {
            texColorTypes[texIdx] = kAlpha_8_SkColorType;
        } else {
            texColorTypes[texIdx] = kRGBA_8888_SkColorType;
        }
    }
    // If UV is interleaved, then Y will have RGBA color type
    if (kRGBA_8888_SkColorType == texColorTypes[yuvaIndices[SkYUVAIndex::kU_Index].fIndex]) {
        texColorTypes[yuvaIndices[SkYUVAIndex::kY_Index].fIndex] = kRGBA_8888_SkColorType;
    }

    // Get lazy proxies
    GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
    sk_sp<GrTextureProxy> proxies[4];
    for (int texIdx = 0; texIdx < numTextures; ++texIdx) {
        // for each proxy we need to fill in
        struct {
            GrPixelConfig fConfig;
            SkPromiseImageHelper fPromiseHelper;
        } params;
        if (!context->contextPriv().caps()->getConfigFromBackendFormat(yuvaFormats[texIdx],
                                                                       texColorTypes[texIdx],
                                                                       &params.fConfig)) {
            return nullptr;
        }
        params.fPromiseHelper = promiseHelpers[texIdx];

        GrProxyProvider::LazyInstantiateCallback lazyInstCallback =
            [params](GrResourceProvider* resourceProvider) mutable {
            if (!resourceProvider || !params.fPromiseHelper.isValid()) {
                if (params.fPromiseHelper.isValid()) {
                    params.fPromiseHelper.reset();
                }
                return sk_sp<GrTexture>();
            }

            return params.fPromiseHelper.getTexture(resourceProvider, params.fConfig);
        };
        GrSurfaceDesc desc;
        desc.fFlags = kNone_GrSurfaceFlags;
        desc.fWidth = yuvaSizes[texIdx].width();
        desc.fHeight = yuvaSizes[texIdx].height();
        desc.fConfig = params.fConfig;
        desc.fSampleCnt = 1;
        proxies[texIdx] = proxyProvider->createLazyProxy(
                            std::move(lazyInstCallback), desc, imageOrigin, GrMipMapped::kNo,
                            GrTextureType::k2D, GrInternalSurfaceFlags::kNone,
                            SkBackingFit::kExact, SkBudgeted::kNo,
                            GrSurfaceProxy::LazyInstantiationType::kUninstantiate);
        if (!proxies[texIdx]) {
            return nullptr;
        }
    }

    return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(context), imageWidth, imageHeight,
                                       kNeedNewImageUniqueID, yuvColorSpace, proxies, yuvaIndices,
                                       imageOrigin, std::move(imageColorSpace), SkBudgeted::kNo);
}

<commit_msg>Fix YUVA index check<commit_after>/*
 * Copyright 2018 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include <cstddef>
#include <cstring>
#include <type_traits>

#include "GrClip.h"
#include "GrContext.h"
#include "GrContextPriv.h"
#include "GrRenderTargetContext.h"
#include "GrTexture.h"
#include "SkImage_Gpu.h"
#include "SkImage_GpuYUVA.h"
#include "effects/GrYUVtoRGBEffect.h"

SkImage_GpuYUVA::SkImage_GpuYUVA(sk_sp<GrContext> context, int width, int height, uint32_t uniqueID,
                                 SkYUVColorSpace colorSpace, sk_sp<GrTextureProxy> proxies[],
                                 const SkYUVAIndex yuvaIndices[4],  GrSurfaceOrigin origin,
                                 sk_sp<SkColorSpace> imageColorSpace, SkBudgeted budgeted)
        : INHERITED(std::move(context), width, height, uniqueID,
                    // If an alpha channel is present we always switch to kPremul. This is because,
                    // although the planar data is always un-premul, the final interleaved RGB image
                    // is/would-be premul.
                    -1 != yuvaIndices[SkYUVAIndex::kA_Index].fIndex ? kPremul_SkAlphaType
                                                                    : kOpaque_SkAlphaType,
                    budgeted, imageColorSpace)
        , fYUVColorSpace(colorSpace)
        , fOrigin(origin) {
    int maxIndex = yuvaIndices[0].fIndex;
    for (int i = 1; i < 4; ++i) {
        if (yuvaIndices[i].fIndex > maxIndex) {
            maxIndex = yuvaIndices[i].fIndex;
        }
    }
    for (int i = 0; i <= maxIndex; ++i) {
        fProxies[i] = std::move(proxies[i]);
    }
    memcpy(fYUVAIndices, yuvaIndices, 4*sizeof(SkYUVAIndex));
}

SkImage_GpuYUVA::~SkImage_GpuYUVA() {}

SkImageInfo SkImage_GpuYUVA::onImageInfo() const {
    // Note: this is the imageInfo for the flattened image, not the YUV planes
    return SkImageInfo::Make(this->width(), this->height(), kRGBA_8888_SkColorType,
                             fAlphaType, fColorSpace);
}

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

sk_sp<GrTextureProxy> SkImage_GpuYUVA::asTextureProxyRef() const {
    if (!fRGBProxy) {
        sk_sp<GrTextureProxy> yProxy = fProxies[fYUVAIndices[SkYUVAIndex::kY_Index].fIndex];
        sk_sp<GrTextureProxy> uProxy = fProxies[fYUVAIndices[SkYUVAIndex::kU_Index].fIndex];
        sk_sp<GrTextureProxy> vProxy = fProxies[fYUVAIndices[SkYUVAIndex::kV_Index].fIndex];

        if (!yProxy || !uProxy || !vProxy) {
            return nullptr;
        }

        GrPaint paint;
        paint.setPorterDuffXPFactory(SkBlendMode::kSrc);

        // TODO: modify the YUVtoRGBEffect to do premul if fImageAlphaType is kPremul_AlphaType
        paint.addColorFragmentProcessor(GrYUVtoRGBEffect::Make(fProxies, fYUVAIndices,
                                                               fYUVColorSpace));

        const SkRect rect = SkRect::MakeIWH(this->width(), this->height());

        // Needs to create a render target in order to draw to it for the yuv->rgb conversion.
        sk_sp<GrRenderTargetContext> renderTargetContext(
            fContext->contextPriv().makeDeferredRenderTargetContext(
                SkBackingFit::kExact, this->width(), this->height(), kRGBA_8888_GrPixelConfig,
                std::move(fColorSpace), 1, GrMipMapped::kNo, fOrigin));
        if (!renderTargetContext) {
            return nullptr;
        }
        renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect);

        if (!renderTargetContext->asSurfaceProxy()) {
            return nullptr;
        }

        // DDL TODO: in the promise image version we must not flush here
        fContext->contextPriv().flushSurfaceWrites(renderTargetContext->asSurfaceProxy());

        fRGBProxy = renderTargetContext->asTextureProxyRef();
    }

    return fRGBProxy;
}

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

//*** bundle this into a helper function used by this and SkImage_Gpu?
sk_sp<SkImage> SkImage_GpuYUVA::MakeFromYUVATextures(GrContext* ctx,
                                                     SkYUVColorSpace colorSpace,
                                                     const GrBackendTexture yuvaTextures[],
                                                     const SkYUVAIndex yuvaIndices[4],
                                                     int width,
                                                     int height,
                                                     GrSurfaceOrigin origin,
                                                     sk_sp<SkColorSpace> imageColorSpace) {
    GrProxyProvider* proxyProvider = ctx->contextPriv().proxyProvider();

    // Right now this still only deals with YUV and NV12 formats. Assuming that YUV has different
    // textures for U and V planes, while NV12 uses same texture for U and V planes.
    bool nv12 = (yuvaIndices[SkYUVAIndex::kU_Index].fIndex ==
                 yuvaIndices[SkYUVAIndex::kV_Index].fIndex);

    // We need to make a copy of the input backend textures because we need to preserve the result
    // of validate_backend_texture.
    GrBackendTexture yuvaTexturesCopy[4];
    for (int i = 0; i < 4; ++i) {
        // Validate that the yuvaIndices refer to valid backend textures.
        const SkYUVAIndex& yuvaIndex = yuvaIndices[i];
        if (SkYUVAIndex::kA_Index == i && yuvaIndex.fIndex == -1) {
            // Meaning the A plane isn't passed in.
            continue;
        }
        if (yuvaIndex.fIndex == -1 || yuvaIndex.fIndex > 3) {
            // Y plane, U plane, and V plane must refer to image sources being passed in. There are
            // at most 4 image sources being passed in, could not have a index more than 3.
            return nullptr;
        }
        SkColorType ct = kUnknown_SkColorType;
        if (SkYUVAIndex::kY_Index == i || SkYUVAIndex::kA_Index == i) {
            // The Y and A planes are always kAlpha8 (for now)
            ct = kAlpha_8_SkColorType;
        } else {
            // The UV planes can either be interleaved or planar
            ct = nv12 ? kRGBA_8888_SkColorType : kAlpha_8_SkColorType;
        }

        if (!yuvaTexturesCopy[yuvaIndex.fIndex].isValid()) {
            yuvaTexturesCopy[yuvaIndex.fIndex] = yuvaTextures[yuvaIndex.fIndex];
            // TODO: Instead of using assumption about whether it is NV12 format to guess colorType,
            // actually use channel information here.
            if (!ValidateBackendTexture(ctx, yuvaTexturesCopy[yuvaIndex.fIndex],
                                        &yuvaTexturesCopy[yuvaIndex.fIndex].fConfig,
                                        ct, kUnpremul_SkAlphaType, nullptr)) {
                return nullptr;
            }
        }

        // TODO: Check that for each plane, the channel actually exist in the image source we are
        // reading from.
    }

    sk_sp<GrTextureProxy> tempTextureProxies[4]; // build from yuvaTextures
    for (int i = 0; i < 4; ++i) {
        // Fill in tempTextureProxies to avoid duplicate texture proxies.
        int textureIndex = yuvaIndices[i].fIndex;

        // Safely ignore since this means we are missing the A plane.
        if (textureIndex == -1) {
            SkASSERT(SkYUVAIndex::kA_Index == i);
            continue;
        }

        if (!tempTextureProxies[textureIndex]) {
            SkASSERT(yuvaTexturesCopy[textureIndex].isValid());
            tempTextureProxies[textureIndex] =
                proxyProvider->wrapBackendTexture(yuvaTexturesCopy[textureIndex], origin);
            if (!tempTextureProxies[textureIndex]) {
                return nullptr;
            }
        }
    }

    return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(ctx), width, height, kNeedNewImageUniqueID,
                                       colorSpace, tempTextureProxies, yuvaIndices, origin,
                                       imageColorSpace, SkBudgeted::kYes);
}

/////////////////////////////////////////////////////////////////////////////////////////////////
sk_sp<SkImage> SkImage_GpuYUVA::MakePromiseYUVATexture(GrContext* context,
                                                       SkYUVColorSpace yuvColorSpace,
                                                       const GrBackendFormat yuvaFormats[],
                                                       const SkISize yuvaSizes[],
                                                       const SkYUVAIndex yuvaIndices[4],
                                                       int imageWidth,
                                                       int imageHeight,
                                                       GrSurfaceOrigin imageOrigin,
                                                       sk_sp<SkColorSpace> imageColorSpace,
                                                       TextureFulfillProc textureFulfillProc,
                                                       TextureReleaseProc textureReleaseProc,
                                                       PromiseDoneProc promiseDoneProc,
                                                       TextureContext textureContexts[]) {
    // The contract here is that if 'promiseDoneProc' is passed in it should always be called,
    // even if creation of the SkImage fails.
    if (!promiseDoneProc) {
        return nullptr;
    }

    int numTextures;
    bool valid = SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures);

    // Set up promise helpers
    SkPromiseImageHelper promiseHelpers[4];
    for (int texIdx = 0; texIdx < numTextures; ++texIdx) {
        promiseHelpers[texIdx].set(textureFulfillProc, textureReleaseProc, promiseDoneProc,
                                   textureContexts[texIdx]);
    }

    if (!valid) {
        return nullptr;
    }

    if (!context) {
        return nullptr;
    }

    if (imageWidth <= 0 || imageWidth <= 0) {
        return nullptr;
    }

    if (!textureFulfillProc || !textureReleaseProc) {
        return nullptr;
    }

    SkAlphaType at = (-1 != yuvaIndices[SkYUVAIndex::kA_Index].fIndex) ? kPremul_SkAlphaType
                                                                       : kOpaque_SkAlphaType;
    SkImageInfo info = SkImageInfo::Make(imageWidth, imageHeight, kRGBA_8888_SkColorType,
                                         at, imageColorSpace);
    if (!SkImageInfoIsValid(info)) {
        return nullptr;
    }

    // Set up color types
    SkColorType texColorTypes[4] = { kUnknown_SkColorType, kUnknown_SkColorType,
                                     kUnknown_SkColorType, kUnknown_SkColorType };
    for (int yuvIndex = 0; yuvIndex < 4; ++yuvIndex) {
        int texIdx = yuvaIndices[yuvIndex].fIndex;
        if (texIdx < 0) {
            SkASSERT(SkYUVAIndex::kA_Index == yuvIndex);
            continue;
        }
        if (kUnknown_SkColorType == texColorTypes[texIdx]) {
            texColorTypes[texIdx] = kAlpha_8_SkColorType;
        } else {
            texColorTypes[texIdx] = kRGBA_8888_SkColorType;
        }
    }
    // If UV is interleaved, then Y will have RGBA color type
    if (kRGBA_8888_SkColorType == texColorTypes[yuvaIndices[SkYUVAIndex::kU_Index].fIndex]) {
        texColorTypes[yuvaIndices[SkYUVAIndex::kY_Index].fIndex] = kRGBA_8888_SkColorType;
    }

    // Get lazy proxies
    GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
    sk_sp<GrTextureProxy> proxies[4];
    for (int texIdx = 0; texIdx < numTextures; ++texIdx) {
        // for each proxy we need to fill in
        struct {
            GrPixelConfig fConfig;
            SkPromiseImageHelper fPromiseHelper;
        } params;
        if (!context->contextPriv().caps()->getConfigFromBackendFormat(yuvaFormats[texIdx],
                                                                       texColorTypes[texIdx],
                                                                       &params.fConfig)) {
            return nullptr;
        }
        params.fPromiseHelper = promiseHelpers[texIdx];

        GrProxyProvider::LazyInstantiateCallback lazyInstCallback =
            [params](GrResourceProvider* resourceProvider) mutable {
            if (!resourceProvider || !params.fPromiseHelper.isValid()) {
                if (params.fPromiseHelper.isValid()) {
                    params.fPromiseHelper.reset();
                }
                return sk_sp<GrTexture>();
            }

            return params.fPromiseHelper.getTexture(resourceProvider, params.fConfig);
        };
        GrSurfaceDesc desc;
        desc.fFlags = kNone_GrSurfaceFlags;
        desc.fWidth = yuvaSizes[texIdx].width();
        desc.fHeight = yuvaSizes[texIdx].height();
        desc.fConfig = params.fConfig;
        desc.fSampleCnt = 1;
        proxies[texIdx] = proxyProvider->createLazyProxy(
                            std::move(lazyInstCallback), desc, imageOrigin, GrMipMapped::kNo,
                            GrTextureType::k2D, GrInternalSurfaceFlags::kNone,
                            SkBackingFit::kExact, SkBudgeted::kNo,
                            GrSurfaceProxy::LazyInstantiationType::kUninstantiate);
        if (!proxies[texIdx]) {
            return nullptr;
        }
    }

    return sk_make_sp<SkImage_GpuYUVA>(sk_ref_sp(context), imageWidth, imageHeight,
                                       kNeedNewImageUniqueID, yuvColorSpace, proxies, yuvaIndices,
                                       imageOrigin, std::move(imageColorSpace), SkBudgeted::kNo);
}

<|endoftext|>