From 4563ef4749689cfb0e59938e8f18670c43f867f9 Mon Sep 17 00:00:00 2001
From: Arfouy <yussef.arfu@nure.ua>
Date: Mon, 6 Mar 2023 14:10:58 +0100
Subject: [PATCH] code rapl v0

---
 main.py | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 rapl.py |  52 ++++++++++++++++++
 2 files changed, 212 insertions(+)
 create mode 100644 main.py
 create mode 100644 rapl.py

diff --git a/main.py b/main.py
new file mode 100644
index 0000000..2112eb2
--- /dev/null
+++ b/main.py
@@ -0,0 +1,160 @@
+import math
+import os
+import sched
+import string
+import sys
+import time
+import types
+import ctypes
+
+from cpuid import *
+from msr import *
+from ctypes.util import find_library
+
+# rapl msr availability
+MSR_SUPPORT_MASK = 0xff
+msr_support_table = None
+
+# Global Variables
+num_nodes = 0
+num_core_threads = 0 # number of physical threads per core
+num_pkg_threads = 0  # number of physical threads per package
+num_pkg_cores = 0    # number of cores per package
+os_cpu_count = 0     # number of OS CPUs
+
+os_map = None
+pkg_map = None
+
+# Pre-computed variables used for time-window calculation
+LN2 = 0.69314718055994530941723212145817656807550013436025
+A_F = [1.0, 1.1, 1.2, 1.3]
+A_LNF = [
+    0.0000000000000000000000000000000000000000000000000000000,
+    0.0953101798043249348602046211453853175044059753417968750,
+    0.1823215567939545922460098381634452380239963531494140625,
+    0.2623642644674910595625760834082029759883880615234375000]
+class rapl_unit_multiplier_t:
+    def __init__(self):
+        self.power = 0.0
+        self.energy = 0.0
+        self.time = 0.0
+
+class rapl_power_limit_control_t:
+    def __init__(self):
+        self.power_limit_watts = 0.0
+        self.limit_time_window_seconds = 0.0
+        self.limit_enabled = 0
+        self.clamp_enabled = 0
+        self.lock_enabled = 0
+
+class rapl_parameters_t:
+    def __init__(self):
+        self.thermal_spec_power_watts = 0.0
+        self.minimum_power_watts = 0.0
+        self.maximum_power_watts = 0.0
+        self.maximum_limit_time_window_seconds = 0.0
+# Define constants and types
+MY_ERROR = -1
+size_t = ctypes.c_size_t
+cpu_set_t = ctypes.c_uint64 * ((os.cpu_count() + 63) // 64)
+
+# Load necessary libraries
+libc_path = find_library('c')
+libc = ctypes.CDLL(libc_path, use_errno=True)
+
+def bind_context(new_context, old_context):
+    error = 0
+
+    ret = 0
+
+    if old_context is not None:
+        old_context_size = size_t(ctypes.sizeof(cpu_set_t))
+        error = libc.sched_getaffinity(0, old_context_size, old_context)
+
+        if error != 0:
+
+            ret = MY_ERROR
+
+    new_context_size = size_t(ctypes.sizeof(cpu_set_t))
+    error += libc.sched_setaffinity(0, new_context_size, new_context)
+
+    if error != 0:
+
+        ret = MY_ERROR
+
+    return ret
+
+def bind_cpu(cpu, old_context):
+    error = 0
+
+    cpu_context = cpu_set_t()
+
+    libc.CPU_ZERO(ctypes.byref(cpu_context))
+    libc.CPU_SET(cpu, ctypes.byref(cpu_context))
+    error += bind_context(ctypes.byref(cpu_context), old_context)
+
+    return error
+
+def parse_apic_id(info_l0, info_l1):
+    # Get the SMT ID
+    smt_mask_width = info_l0.eax & 0x1f
+    smt_mask = ~((-1) << smt_mask_width)
+    smt_id = info_l0.edx & smt_mask
+
+    # Get the core ID
+    core_mask_width = info_l1.eax & 0x1f
+    core_mask = (~((-1) << core_mask_width)) ^ smt_mask
+    core_id = (info_l1.edx & core_mask) >> smt_mask_width
+
+    # Get the package ID
+    pkg_mask = (-1) << core_mask_width
+    pkg_id = (info_l1.edx & pkg_mask) >> core_mask_width
+
+    return {"smt_id": smt_id, "core_id": core_id, "pkg_id": pkg_id}
+
+def build_topology():
+    global os_map, pkg_map, num_nodes, num_pkg_cores, num_pkg_threads, num_core_threads, os_cpu_count
+
+    error = 0
+    max_pkg = 0
+    os_cpu_count = os.cpu_count()
+    os_map = [None] * os_cpu_count
+
+    # Construct an os map: os_map[APIC_ID ... APIC_ID]
+    for i in range(os_cpu_count):
+        prev_context = cpu_set_t()
+        error = bind_cpu(i, prev_context)
+
+        info_l0 = get_processor_topology(0)
+        info_l1 = get_processor_topology(1)
+
+        os_map[i] = APIC_ID_t()
+        os_map[i].os_id = i
+        parse_apic_id(info_l0, info_l1, os_map[i])
+
+        num_core_threads = info_l0.ebx & 0xffff
+        num_pkg_threads = info_l1.ebx & 0xffff
+
+        if os_map[i].pkg_id > max_pkg:
+            max_pkg = os_map[i].pkg_id
+
+        bind_context(prev_context, None)
+
+        # print(f"smt_id: {os_map[i].smt_id} core_id: {os_map[i].core_id} pkg_id: {os_map[i].pkg_id} os_id: {os_map[i].os_id}")
+
+    num_pkg_cores = num_pkg_threads // num_core_threads
+    num_nodes = max_pkg + 1
+
+    # Construct a pkg map: pkg_map[pkg id][APIC_ID ... APIC_ID]
+    pkg_map = [[None] * num_pkg_threads for _ in range(num_nodes)]
+
+    for i in range(os_cpu_count):
+        p = os_map[i].pkg_id
+        t = os_map[i].smt_id * num_pkg_cores + os_map[i].core_id
+        pkg_map[p][t] = os_map[i]
+
+    for i in range(num_nodes):
+        for j in range(num_pkg_threads):
+            print(f"smt_id: {pkg_map[i][j].smt_id} core_id: {pkg_map[i][j].core_id} pkg_id: {pkg_map[i][j].pkg_id} os_id: {pkg_map[i][j].os_id}")
+
+    return error
diff --git a/rapl.py b/rapl.py
new file mode 100644
index 0000000..2ec8522
--- /dev/null
+++ b/rapl.py
@@ -0,0 +1,52 @@
+import psutil
+import time
+import platform
+
+def get_energy():
+    cpu_power = 0
+    mem_power = 0
+    if platform.system() == 'Linux':
+        with open('/sys/devices/virtual/powercap/intel-rapl/intel-rapl:0/energy_uj', 'r') as f:
+            cpu_energy_before = int(f.read().strip())
+        with open('/sys/devices/virtual/powercap/intel-rapl/intel-rapl:0/intel-rapl:0:1/energy_uj', 'r') as f:
+            mem_energy_before = int(f.read().strip())
+        time.sleep(1)
+        with open('/sys/devices/virtual/powercap/intel-rapl/intel-rapl:0/energy_uj', 'r') as f:
+            cpu_energy_after = int(f.read().strip())
+        with open('/sys/devices/virtual/powercap/intel-rapl/intel-rapl:0/intel-rapl:0:1/energy_uj', 'r') as f:
+            mem_energy_after = int(f.read().strip())
+        cpu_energy_diff = cpu_energy_after - cpu_energy_before
+        mem_energy_diff = mem_energy_after - mem_energy_before
+        cpu_power = cpu_energy_diff / 1000000 # Convert uJ to mJ
+        mem_power = mem_energy_diff / 1000000 # Convert uJ to mJ
+    elif platform.system() == 'Windows':
+        cpu_percent_before = psutil.cpu_percent()
+        mem_percent_before = psutil.virtual_memory().percent
+        time.sleep(1)
+        cpu_percent_after = psutil.cpu_percent()
+        mem_percent_after = psutil.virtual_memory().percent
+        cpu_percent_diff = cpu_percent_after - cpu_percent_before
+        mem_percent_diff = mem_percent_after - mem_percent_before
+        cpu_power = cpu_percent_diff / 100 * psutil.cpu_count() * psutil.cpu_freq().current / 1000
+        mem_power = mem_percent_diff / 100 * psutil.virtual_memory().total / 1024 / 1024 / 1024 * 3.3
+    return (cpu_power, mem_power)
+
+print('Press Enter to start measuring energy consumption...')
+input()
+cpu_power_before, mem_power_before = get_energy()
+print('Please write "math formula, word text, excel" using the virtual keyboard...')
+while True:
+    try:
+        cpu_power, mem_power = get_energy()
+        cpu_power_diff = cpu_power - cpu_power_before
+        mem_power_diff = mem_power - mem_power_before
+        print(f'CPU energy consumption: {cpu_power_diff:.2f} mJ')
+        print(f'Memory energy consumption: {mem_power_diff:.2f} mJ')
+        time.sleep(1)
+    except KeyboardInterrupt:
+        break
+cpu_power_after, mem_power_after = get_energy()
+cpu_power_diff = cpu_power_after - cpu_power_before
+mem_power_diff = mem_power_after - mem_power_before
+print(f'Total CPU energy consumption: {cpu_power_diff:.2f} mJ')
+print(f'Total memory energy consumption: {mem_power_diff:.2f} mJ')
-- 
GitLab