Exemple #1
0
    def test_use_different_unit_in_performances(self):
        problem1 = self.create_simple_problem(
            time_unit_price="h",
            time_unit_performance="h",
            timeslot="h",
            base_price=100,
            base_perf=1000,
            base_workload=2000,
            n_timeslots=365 * 24,
        )
        phaseI1 = phases.PhaseI(problem1)
        solution1 = phaseI1.solve()
        assert solution1.solving_stats.algorithm.status == Status.optimal

        # Now the same problem, but the performances are expressed in qps instead of rph
        problem2 = self.create_simple_problem(
            time_unit_price="h",
            time_unit_performance="s",
            timeslot="h",
            base_price=100,
            base_perf=1000 / 3600,
            base_workload=2000,
            n_timeslots=365 * 24,
        )
        phaseI2 = phases.PhaseI(problem2)
        solution2 = phaseI2.solve()

        # The solution should be the same, because the performance is the same (only scaled)
        assert solution2.solving_stats.algorithm.status == Status.optimal
        assert (
            solution2.solving_stats.optimal_cost == solution1.solving_stats.optimal_cost
        )
        assert solution2.allocation.values == solution1.allocation.values
Exemple #2
0
    def test_different_units_in_workload(self):
        problem1 = self.create_simple_problem(
            time_unit_price="h",
            time_unit_performance="h",
            timeslot="h",
            base_price=100,
            base_perf=1000,
            base_workload=2000,
            n_timeslots=365 * 24,
        )
        phaseI1 = phases.PhaseI(problem1)
        solution1 = phaseI1.solve()
        assert solution1.solving_stats.algorithm.status == Status.optimal

        # Now solve the same problem, but with the workload in minutes
        problem2 = self.create_simple_problem(
            time_unit_price="h",
            time_unit_performance="h",
            timeslot="m",
            base_price=100,
            base_perf=1000,
            base_workload=2000 / 60,
            n_timeslots=365 * 24 * 60,
        )
        phaseI2 = phases.PhaseI(problem2)
        solution2 = phaseI2.solve()

        # The solution should be the same, because the performance is the same
        assert solution2.solving_stats.algorithm.status == Status.optimal
        assert (
            solution2.solving_stats.optimal_cost == solution1.solving_stats.optimal_cost
        )
        assert solution1.reserved_allocation == solution2.reserved_allocation
Exemple #3
0
    def test_solution_with_hybrid_to_yaml_back_and_forth(self):
        """Creates and solves a problem which uses private instances, 
        converts the solution to YAML, checks that the resulting YAML
        is valid, and finally reads it back to Python and compares it
        with the solution object"""
        problem = create_problem()
        solution = phases.PhaseI(problem).solve()

        # Dump solution to yaml
        from malloovia import util
        yaml_str = util.solutions_to_yaml([solution])
        with open("/tmp/test.yaml", "w") as f:
            f.write(yaml_str)

        # Check that the generated solution is valid against the schema
        solution_data = yaml.safe_load(yaml_str)
        malloovia_schema = util.get_schema()
        try:
            validate(solution_data, malloovia_schema)
        except Exception as e:
            pytest.fail("The generated yaml is not valid against the schema")

        # The actual test is to read it back
        back_to_solution = util.solutions_from_dict(yaml.safe_load(yaml_str),
                                                    yaml_filename="Nofile")
        # Compare malloovia classes to ensure that they store the same information in the
        # original problem.
        assert solution == back_to_solution['solution_i_example']
Exemple #4
0
    def test_solve_problem_with_private_constraints(self):
        """This test creates and solves one problem in which the private cloud
        imposes limits on the maximum number of cores"""
        problem = create_problem()
        phase_i = phases.PhaseI(problem)
        solution = phase_i.solve()
        assert solution.solving_stats.algorithm.status == Status.optimal

        # The cost of the optimal solution has to be 252.0 for this problem
        assert solution.solving_stats.optimal_cost == 252.0

        # There is a single private limiting set
        private_limiting_sets = set(ls for ic in problem.instance_classes
                                    if ic.is_private
                                    for ls in ic.limiting_sets)
        assert len(private_limiting_sets) == 1
        private_limiting_set = list(private_limiting_sets)[0]

        # That limiting set imposes a limit in the number of cores
        max_cores = private_limiting_set.max_cores
        assert max_cores == 20

        # The solution does not violate the max_cores limit
        used_cores = []
        for ts_alloc in solution.allocation.values:
            used_cores_in_ts = 0
            for app_alloc in ts_alloc:
                for i, ic_number in enumerate(app_alloc):
                    ic = solution.allocation.instance_classes[i]
                    if ic.is_private:
                        used_cores_in_ts += ic_number * ic.cores
            used_cores.append(used_cores_in_ts)

        assert all(n_cores <= max_cores for n_cores in used_cores)
Exemple #5
0
    def test_use_different_unit_in_prices(self):
        problem1 = self.create_simple_problem(
            time_unit_price="h",
            time_unit_performance="h",
            timeslot="h",
            base_price=100,
            base_perf=1000,
            base_workload=2000,
            n_timeslots=365 * 24,
        )
        phaseI1 = phases.PhaseI(problem1)
        solution1 = phaseI1.solve()
        assert solution1.solving_stats.algorithm.status == Status.optimal

        # Now solve the same problem, but with the prices in minutes, not scaled
        problem2 = self.create_simple_problem(
            time_unit_price="m",
            time_unit_performance="h",
            timeslot="h",
            base_price=100,
            base_perf=1000,
            base_workload=2000,
            n_timeslots=365 * 24,
        )
        phaseI2 = phases.PhaseI(problem2)
        solution2 = phaseI2.solve()

        # Since 100 is now the price per minute instead of per hour, the total cost should
        # be 60 times the one of the first problem
        assert solution2.solving_stats.algorithm.status == Status.optimal
        assert (
            solution2.solving_stats.optimal_cost
            == 60 * solution1.solving_stats.optimal_cost
        )
        # But, except for the cost, the solution is equivalent
        assert solution2.allocation.values == solution1.allocation.values
Exemple #6
0
    def test_use_different_unit_in_phaseII_workload(self):
        # In phase I, the prices and performances are expressed per hour
        # The workload is also per hour. To reduce the size of the problem,
        # we use 24h as reservation period instead of 8760
        phase_i_problem = self.create_simple_problem(
            time_unit_price="h",
            time_unit_performance="h",
            timeslot="h",
            base_price=100,
            base_perf=1000,
            base_workload=2000,
            n_timeslots=24,
        )
        phaseI = phases.PhaseI(phase_i_problem)
        solution_i = phaseI.solve()
        assert solution_i.solving_stats.algorithm.status == Status.optimal

        # For phase II, we keep the same instance classes (prices and performances)
        # but use a STWP expressed in minutes
        app0 = phase_i_problem.workloads[0].app
        phase_ii_problem = phase_i_problem._replace(
            workloads=(
                Workload(
                    "wl_app0",
                    description="Test",
                    app=app0,
                    values=(2000 / 3600,) * 24 * 60,
                    time_unit="m",
                ),
            )
        )
        phase_ii = phases.PhaseII(problem=phase_ii_problem, phase_i_solution=solution_i)
        solution_ii = phase_ii.solve_period()

        # Since the workload was scaled, it is essentially the same, so the phase II solution
        # should be equal to phase I solution, except for rounding errors
        assert (
            abs(
                solution_ii.global_solving_stats.optimal_cost
                - solution_i.solving_stats.optimal_cost
            )
            <= 0.0001
        )