Source code for perfsim.equipments.core

#  Copyright (C) 2020 Michel Gokan Khan
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License along
#  with this program; if not, write to the Free Software Foundation, Inc.,
#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
#  This file is a part of the PerfSim project, which is now open source and available under the GPLv2.
#  Written by Michel Gokan Khan, February 2020


from __future__ import annotations

import math
from typing import TYPE_CHECKING, Union

from perfsim import RunQueue, Resource, Observable, CoreLogObserver

if TYPE_CHECKING:
    from perfsim import CPU


[docs] class Core(Resource, Observable): """ This class represents a core in a CPU. A core is a processing unit that can execute threads. It has a run queue that contains the threads that are currently assigned to it. The core can execute threads for a certain duration. """ #: The CPU that this core belongs to __cpu: CPU #: The core's unique identifier in the CPU id_in_cpu: int #: The run queue that this core is currently assigned to. runqueue: RunQueue def __init__(self, cpu: CPU, core_id: Union[str, int], core_id_in_cpu: int): name = "core_" + str(core_id) self.core_id = core_id self.id_in_cpu = core_id_in_cpu self.pair_id = int(math.floor(self.id_in_cpu / 2)) super().__init__(type="core", name=name, throttleable=True, unit_of_measure="shares", capacity=cpu.max_cpu_requests) self.cpu = cpu self.runqueue = RunQueue(core=self) Observable.__init__(self) if cpu.host.cluster is not None and cpu.host.cluster.sim.debug: self.attach_observer(CoreLogObserver(core=self))
[docs] def reinit(self): """ Reinitialize the core :return: """ self.__init__(cpu=self.cpu, core_id=self.core_id, core_id_in_cpu=self.id_in_cpu)
[docs] def register_events(self): """ Register events for the core :return: """ self.register_event("on_thread_completion")
[docs] def get_core_clock_cycle(self) -> float: """ Returns the clock cycle of the core :return: """ return 1 / self.cpu.clock_rate
[docs] def exec_threads(self, duration: Union[int, float]) -> int: """ Executes threads on the core for `duration` nanoseconds :param: duration: The execution duration """ completed_threads = 0 thread_id = 0 simultaneous_flag = False prev_total_be_threads = len(self.runqueue.best_effort_active_threads) #: BE = Best Effort prev_total_ge_cpu_rqsts = self.runqueue.guaranteed_active_threads.sum_cpu_requests #: GE = Guaranteed rq_prev_active_threads = 0 if len(self.runqueue.rq) == 0: self.runqueue.run_idle(duration=duration) else: while thread_id < len(self.runqueue.rq): thread = self.runqueue.rq[thread_id] if thread.on_rq and thread.instructions != 0: thread.exec(duration, simultaneous_flag) simultaneous_flag = True if thread.instructions <= 0: self.notify_observers(event_name="on_thread_completion") completed_threads += 1 thread_id += 1 rq_prev_active_threads += 1 else: thread_id += 1 raise Exception("I'm not sure, but I believe there might be a potential bug here!") if not prev_total_be_threads and prev_total_ge_cpu_rqsts < self.cpu.max_cpu_requests and rq_prev_active_threads: ratio_of_idle = (self.cpu.max_cpu_requests - prev_total_ge_cpu_rqsts) / self.cpu.max_cpu_requests self.runqueue.threads_total_time["idle"][int(self.cpu.host.cluster.sim.time)] = duration * ratio_of_idle return completed_threads
def __str__(self): """ Returns the string representation of the core :return: """ return "host_" + str(self.cpu.host) + "_cpu_" + str(self.cpu) + "_core_" + str(self.id_in_cpu)