diff --git a/rteval/modules/loads/kcompile.py b/rteval/modules/loads/kcompile.py
index 2c93c794fe75..4a8659c042e6 100644
--- a/rteval/modules/loads/kcompile.py
+++ b/rteval/modules/loads/kcompile.py
@@ -33,8 +33,10 @@ import subprocess
 from rteval.modules import rtevalRuntimeError
 from rteval.modules.loads import CommandLineLoad
 from rteval.Log import Log
-from rteval.misc import expand_cpulist, compress_cpulist
-from rteval.systopology import SysTopology
+from rteval.systopology import CpuList, SysTopology
+
+expand_cpulist = CpuList.expand_cpulist
+compress_cpulist = CpuList.compress_cpulist
 
 DEFAULT_KERNEL_PREFIX = "linux-5.18"
 
@@ -48,21 +50,21 @@ class KBuildJob:
         self.logger = logger
         self.binder = None
         self.builddir = os.path.dirname(kdir)
-        self.objdir = "%s/node%d" % (self.builddir, int(node))
+        self.objdir = f"{self.builddir}/node{int(node)}"
 
         if not os.path.isdir(self.objdir):
             os.mkdir(self.objdir)
 
         if os.path.exists('/usr/bin/numactl') and not cpulist:
-            """ Use numactl """
-            self.binder = 'numactl --cpunodebind %d' % int(self.node)
+            # Use numactl
+            self.binder = f'numactl --cpunodebind {int(self.node)}'
             self.jobs = self.calc_jobs_per_cpu() * len(self.node)
         elif cpulist:
-            """ Use taskset """
+            # Use taskset
             self.jobs = self.calc_jobs_per_cpu() * len(cpulist)
-            self.binder = 'taskset -c %s' % compress_cpulist(cpulist)
+            self.binder = f'taskset -c {compress_cpulist(cpulist)}'
         else:
-            """ Without numactl calculate number of jobs from the node """
+            # Without numactl calculate number of jobs from the node
             self.jobs = self.calc_jobs_per_cpu() * len(self.node)
 
         self.runcmd = f"make O={self.objdir} -C {self.kdir} -j{self.jobs}"
@@ -72,56 +74,61 @@ class KBuildJob:
             self.runcmd = self.binder + " " + self.runcmd
             self.cleancmd = self.binder + " " + self.cleancmd
 
-        self.log(Log.DEBUG, "node %d: jobs == %d" % (int(node), self.jobs))
+        self.log(Log.DEBUG, f"node {int(node)}: jobs == {self.jobs}")
         self.log(Log.DEBUG, f"cleancmd = {self.cleancmd}")
-        self.log(Log.DEBUG, "node%d kcompile command: %s" \
-                % (int(node), self.runcmd))
+        self.log(Log.DEBUG, f"node{int(node)} kcompile command: {self.runcmd}")
 
     def __str__(self):
         return self.runcmd
 
     def log(self, logtype, msg):
+        """ starting logging for the kcompile module """
         if self.logger:
-            self.logger.log(logtype, "[kcompile node%d] %s" % (int(self.node), msg))
+            self.logger.log(logtype, f"[kcompile node{int(self.node)}] {msg}")
 
     def calc_jobs_per_cpu(self):
+        """ Calculate the number of kcompile jobs to do """
         mult = 2
-        self.log(Log.DEBUG, "calulating jobs for node %d" % int(self.node))
+        self.log(Log.DEBUG, f"calulating jobs for node {int(self.node)}")
         # get memory total in gigabytes
         mem = int(self.node.meminfo['MemTotal']) / 1024.0 / 1024.0 / 1024.0
         # ratio of gigabytes to #cores
         ratio = float(mem) / float(len(self.node))
-        if ratio < 1.0:
-            ratio = 1.0
-        if ratio < 1.0 or ratio > 2.0:
+        ratio = max(ratio, 1.0)
+        if ratio > 2.0:
             mult = 1
-        self.log(Log.DEBUG, "memory/cores ratio on node %d: %f" % (int(self.node), ratio))
-        self.log(Log.DEBUG, "returning jobs/core value of: %d" % int(ratio) * mult)
+        self.log(Log.DEBUG, f"memory/cores ratio on node {int(self.node)}: {ratio}")
+        self.log(Log.DEBUG, f"returning jobs/core value of: {int(ratio) * mult}")
         return int(int(ratio) * int(mult))
 
     def clean(self, sin=None, sout=None, serr=None):
-        self.log(Log.DEBUG, "cleaning objdir %s" % self.objdir)
+        """ Runs command to clean any previous builds and configure kernel """
+        self.log(Log.DEBUG, f"cleaning objdir {self.objdir}")
         subprocess.call(self.cleancmd, shell=True,
                         stdin=sin, stdout=sout, stderr=serr)
 
     def run(self, sin=None, sout=None, serr=None):
-        self.log(Log.INFO, "starting workload on node %d" % int(self.node))
-        self.log(Log.DEBUG, "running on node %d: %s" % (int(self.node), self.runcmd))
+        """ Use Popen to launch a kcompile job """
+        self.log(Log.INFO, f"starting workload on node {int(self.node)}")
+        self.log(Log.DEBUG, f"running on node {int(self.node)}: {self.runcmd}")
         self.jobid = subprocess.Popen(self.runcmd, shell=True,
                                       stdin=sin, stdout=sout, stderr=serr)
 
     def isrunning(self):
+        """ Query whether a job is running, returns True or False """
         if self.jobid is None:
             return False
         return self.jobid.poll() is None
 
     def stop(self):
+        """ stop a kcompile job """
         if not self.jobid:
             return True
         return self.jobid.terminate()
 
 
 class Kcompile(CommandLineLoad):
+    """ class to compile the kernel as an rteval load """
     def __init__(self, config, logger):
         self.buildjobs = {}
         self.config = config
@@ -150,14 +157,14 @@ class Kcompile(CommandLineLoad):
     def _remove_build_dirs(self):
         if not os.path.isdir(self.builddir):
             return
-        self._log(Log.DEBUG, "removing kcompile directories in %s" % self.builddir)
+        self._log(Log.DEBUG, f"removing kcompile directories in {self.builddir}")
         null = os.open("/dev/null", os.O_RDWR)
         cmd = ["rm", "-rf", os.path.join(self.builddir, "kernel*"),
                os.path.join(self.builddir, "node*")]
         ret = subprocess.call(cmd, stdin=null, stdout=null, stderr=null)
         if ret:
             raise rtevalRuntimeError(self, \
-                "error removing builddir (%s) (ret=%d)" % (self.builddir, ret))
+                f"error removing builddir ({self.buildir}) (ret={ret})")
 
     def _WorkloadSetup(self):
         if self._donotrun:
@@ -167,15 +174,15 @@ class Kcompile(CommandLineLoad):
         if self._cfg.source:
             tarfile = os.path.join(self.srcdir, self._cfg.source)
             if not os.path.exists(tarfile):
-                raise rtevalRuntimeError(self, " tarfile %s does not exist!" % tarfile)
+                raise rtevalRuntimeError(self, f" tarfile {tarfile} does not exist!")
             self.source = tarfile
             kernel_prefix = re.search(r"linux-\d{1,2}\.\d{1,3}", self.source).group(0)
         else:
-            tarfiles = glob.glob(os.path.join(self.srcdir, "%s*" % DEFAULT_KERNEL_PREFIX))
+            tarfiles = glob.glob(os.path.join(self.srcdir, f"{DEFAULT_KERNEL_PREFIX}*"))
             if tarfiles:
                 self.source = tarfiles[0]
             else:
-                raise rtevalRuntimeError(self, " no kernel tarballs found in %s" % self.srcdir)
+                raise rtevalRuntimeError(self, f" no kernel tarballs found in {self.srcdir}")
             kernel_prefix = DEFAULT_KERNEL_PREFIX
         self._log(Log.DEBUG, f"kernel_prefix = {kernel_prefix}")
 
@@ -190,15 +197,15 @@ class Kcompile(CommandLineLoad):
             self._extract_tarball()
             names = os.listdir(self.builddir)
             for d in names:
-                self._log(Log.DEBUG, "checking %s" % d)
+                self._log(Log.DEBUG, f"checking {d}")
                 if d.startswith(kernel_prefix):
                     kdir = d
                     break
         if kdir is None:
             raise rtevalRuntimeError(self, "Can't find kernel directory!")
         self.mydir = os.path.join(self.builddir, kdir)
-        self._log(Log.DEBUG, "mydir = %s" % self.mydir)
-        self._log(Log.DEBUG, "systopology: %s" % self.topology)
+        self._log(Log.DEBUG, f"mydir = {self.mydir}")
+        self._log(Log.DEBUG, f"systopology: {self.topology}")
         self.jobs = len(self.topology)
         self.args = []
 
@@ -217,10 +224,10 @@ class Kcompile(CommandLineLoad):
         for node, cpus in self.cpus.items():
             if not cpus:
                 self.nodes.remove(node)
-                self._log(Log.DEBUG, "node %s has no available cpus, removing" % node)
+                self._log(Log.DEBUG, f"node {node} has no available cpus, removing")
 
         for n in self.nodes:
-            self._log(Log.DEBUG, "Configuring build job for node %d" % int(n))
+            self._log(Log.DEBUG, f"Configuring build job for node {int(n)}")
             self.buildjobs[n] = KBuildJob(self.topology[n], self.mydir, \
                 self.logger, self.cpus[n] if self.cpulist else None)
             self.args.append(str(self.buildjobs[n])+";")
@@ -249,7 +256,7 @@ class Kcompile(CommandLineLoad):
                 ret = subprocess.call(cmd, stdin=null, stdout=out, stderr=err)
                 if ret:
                     # give up
-                    raise rtevalRuntimeError(self, "kcompile setup failed: %d" % ret)
+                    raise rtevalRuntimeError(self, f"kcompile setup failed: {ret}")
         except KeyboardInterrupt as m:
             self._log(Log.DEBUG, "keyboard interrupt, aborting")
             return
@@ -280,15 +287,14 @@ class Kcompile(CommandLineLoad):
     def _WorkloadTask(self):
         for n in self.nodes:
             if not self.buildjobs[n]:
-                raise RuntimeError("Build job not set up for node %d" % int(n))
+                raise RuntimeError(f"Build job not set up for node {int(n)}")
             if self.buildjobs[n].jobid is None or self.buildjobs[n].jobid.poll() is not None:
                 # A jobs was started, but now it finished. Check return code.
                 # -2 is returned when user forced stop of execution (CTRL-C).
                 if self.buildjobs[n].jobid is not None:
-                    if self.buildjobs[n].jobid.returncode != 0 and self.buildjobs[n].jobid.returncode != -2:
-                        raise RuntimeError("kcompile module failed to run (returned %d), please check logs for more detail" \
-                            % self.buildjobs[n].jobid.returncode)
-                self._log(Log.INFO, "Starting load on node %d" % n)
+                    if self.buildjobs[n].jobid.returncode not in (0, -2):
+                        raise RuntimeError(f"kcompile module failed to run (returned {self.buildjobs[n].jobid.returncode}), please check logs for more detail")
+                self._log(Log.INFO, f"Starting load on node {n}")
                 self.buildjobs[n].run(self.__nullfd, self.__outfd, self.__errfd)
 
     def WorkloadAlive(self):
@@ -296,8 +302,8 @@ class Kcompile(CommandLineLoad):
         for n in self.nodes:
             if self.buildjobs[n].jobid.poll() is not None:
                 # Check return code (see above).
-                if self.buildjobs[n].jobid.returncode != 0 and self.buildjobs[n].jobid.returncode != -2:
-                    raise RuntimeError("kcompile module failed to run (returned %d), please check logs for more detail" % self.buildjobs[n].jobid.returncode)
+                if self.buildjobs[n].jobid.returncode not in (0, -2):
+                    raise RuntimeError(f"kcompile module failed to run (returned {self.buildjobs[n].jobid.returncode}), please check logs for more detail")
                 return False
 
         return True
@@ -310,7 +316,7 @@ class Kcompile(CommandLineLoad):
         self._log(Log.DEBUG, "out of stopevent loop")
         for n in self.buildjobs:
             if self.buildjobs[n].jobid.poll() is None:
-                self._log(Log.DEBUG, "stopping job on node %d" % int(n))
+                self._log(Log.DEBUG, f"stopping job on node {int(n)}")
                 self.buildjobs[n].jobid.terminate()
                 self.buildjobs[n].jobid.wait()
                 del self.buildjobs[n].jobid
