diff --git a/general/__init__.py b/general/__init__.py index b320e35..304c5f2 100644 --- a/general/__init__.py +++ b/general/__init__.py @@ -1 +1,3 @@ -from .monitor import * \ No newline at end of file +from .monitor import * +from .hdd import * +from .gpu import * diff --git a/general/stats.py b/general/gpu.py similarity index 50% rename from general/stats.py rename to general/gpu.py index abafe66..e5ee56b 100644 --- a/general/stats.py +++ b/general/gpu.py @@ -1,6 +1,3 @@ -import platform -import cpuinfo -import psutil import torch import pynvml import comfy.model_management @@ -8,10 +5,14 @@ import comfy.model_management from ..core import logger -class CStats: +def getGPUsInfo(): + gpus = [] + + return gpus + +class CGPUInfo: """ - This is only class to get information from hardware. - Specially for share it to other software. + This class is responsible for getting information from GPU (ONLY). """ nvidia = False pynvmlLoaded = False @@ -19,25 +20,11 @@ class CStats: torchDevice = 'cpu' cudaDevice = 'cpu' cudaDevicesFound = 0 - switchCPU = False switchGPU = False - switchHDD = False - switchRAM = False switchVRAM = False - whichHDD = 'C:\\' - - def __init__(self, switchCPU=False, switchGPU=False, switchHDD=False, switchRAM=False, switchVRAM=False): - self.switchCPU = switchCPU - self.switchGPU = switchGPU - self.switchHDD = switchHDD - self.switchRAM = switchRAM - self.switchVRAM = switchVRAM - - specName = 'CPU: ' + cpuinfo.get_cpu_info().get('brand_raw', "Unknown") - specArch = 'Arch: ' + cpuinfo.get_cpu_info().get('arch_string_raw', "Unknown") - specOs = 'OS: ' + str(platform.system()) + ' ' + str(platform.release()) - logger.info(f"{specName} - {specArch} - {specOs}") + def __init__(self): + logger.debug('CGPUInfo init') try: pynvml.nvmlInit() self.pynvmlLoaded = True @@ -45,40 +32,38 @@ class CStats: self.pynvmlLoaded = False logger.error('Could not init pynvml.' + str(e)) - self.diagnostic() + if self.pynvmlLoaded and pynvml.nvmlDeviceGetCount() > 0: + self.cudaDevicesFound = pynvml.nvmlDeviceGetCount() + self.nvidia = True + logger.info( + f'NVIDIA Driver detected - {pynvml.nvmlSystemGetDriverVersion()} - {comfy.model_management.get_torch_device_name(comfy.model_management.get_torch_device())}') + else: + logger.warn('No NVIDIA GPU detected.') - def buildStatsData(self): - cpu = -1 - ramTotal = -1 - ramUsed = -1 - ramUsedPercent = -1 - hddTotal = -1 - hddUsed = -1 - hddUsedPercent = -1 + try: + self.torchDevice = comfy.model_management.get_torch_device_name(comfy.model_management.get_torch_device()) + except Exception as e: + logger.error('Could not pick default device.' + str(e)) + + self.cudaDevice = 'cpu' if self.torchDevice == 'cpu' else 'cuda' + self.cudaAvailable = torch.cuda.is_available() + + if self.nvidia and self.cudaAvailable and self.torchDevice == 'cpu': + logger.warn('CUDA is available, but torch is using CPU.') + + + def getStatus(self): + # logger.debug('CGPUInfo getStatus') gpuUtilization = -1 vramUsed = -1 vramTotal = -1 vramPercent = -1 - if self.switchCPU: - cpu = psutil.cpu_percent() - - if self.switchRAM: - ram = psutil.virtual_memory() - ramTotal = ram.total - ramUsed = ram.used - ramUsedPercent = ram.percent - - if self.switchHDD: - hdd = psutil.disk_usage(self.whichHDD) - hddTotal = hdd.total - hddUsed = hdd.used - hddUsedPercent = hdd.percent - - deviceType = 'cpu' + gpuType = '' gpus = [] if self.cudaDevice == 'cpu': + gpuType = 'cpu' gpus.append({ 'gpu_utilization': -1, 'vram_total': -1, @@ -86,7 +71,7 @@ class CStats: 'vram_used_percent': -1, }) else: - deviceType = self.cudaDevice + gpuType = self.cudaDevice if self.pynvmlLoaded and self.nvidia and self.cudaAvailable: for deviceIndex in range(self.cudaDevicesFound): @@ -104,7 +89,7 @@ class CStats: vramUsed = memory.used vramTotal = memory.total - # device = torch.device(deviceType) + # device = torch.device(gpuType) # vramUsed = torch.cuda.memory_allocated(device) # vramTotal = torch.cuda.get_device_properties(device).total_memory @@ -118,32 +103,6 @@ class CStats: }) return { - 'cpu_utilization': cpu, - 'ram_total': ramTotal, - 'ram_used': ramUsed, - 'ram_used_percent': ramUsedPercent, - 'hdd_total': hddTotal, - 'hdd_used': hddUsed, - 'hdd_used_percent': hddUsedPercent, - 'device_type': deviceType, + 'device_type': gpuType, 'gpus': gpus, } - - def diagnostic(self): - if self.pynvmlLoaded and pynvml.nvmlDeviceGetCount() > 0: - self.cudaDevicesFound = pynvml.nvmlDeviceGetCount() - self.nvidia = True - logger.info(f'NVIDIA Driver detected - {pynvml.nvmlSystemGetDriverVersion()} - {comfy.model_management.get_torch_device_name(comfy.model_management.get_torch_device())}') - else: - logger.warn('No NVIDIA GPU detected.') - - try: - self.torchDevice = comfy.model_management.get_torch_device_name(comfy.model_management.get_torch_device()) - except Exception as e: - logger.error('Could not pick default device.' + str(e)) - - self.cudaDevice = 'cpu' if self.torchDevice == 'cpu' else 'cuda' - self.cudaAvailable = torch.cuda.is_available() - - if self.nvidia and self.cudaAvailable and self.torchDevice == 'cpu': - logger.warn('CUDA is available, but torch is using CPU.') diff --git a/general/hardware.py b/general/hardware.py new file mode 100644 index 0000000..c9e8b42 --- /dev/null +++ b/general/hardware.py @@ -0,0 +1,83 @@ +import platform +import cpuinfo +import psutil +from .gpu import CGPUInfo + +from ..core import logger + + +class CHardwareInfo: + """ + This is only class to get information from hardware. + Specially for share it to other software. + """ + switchCPU = False + switchHDD = False + switchRAM = False + whichHDD = 'C:\\' + + @property + def switchGPU(self): + return self.GPUInfo.switchGPU + @switchGPU.setter + def switchGPU(self, value): + self.GPUInfo.switchGPU = value + + @property + def switchVRAM(self): + return self.GPUInfo.switchVRAM + @switchVRAM.setter + def switchVRAM(self, value): + self.GPUInfo.switchVRAM = value + + def __init__(self, switchCPU=False, switchGPU=False, switchHDD=False, switchRAM=False, switchVRAM=False): + self.switchCPU = switchCPU + self.switchHDD = switchHDD + self.switchRAM = switchRAM + + specName = 'CPU: ' + cpuinfo.get_cpu_info().get('brand_raw', "Unknown") + specArch = 'Arch: ' + cpuinfo.get_cpu_info().get('arch_string_raw', "Unknown") + specOs = 'OS: ' + str(platform.system()) + ' ' + str(platform.release()) + logger.info(f"{specName} - {specArch} - {specOs}") + + self.GPUInfo = CGPUInfo() + self.switchGPU = switchGPU + self.switchVRAM = switchVRAM + + def getStatus(self): + cpu = -1 + ramTotal = -1 + ramUsed = -1 + ramUsedPercent = -1 + hddTotal = -1 + hddUsed = -1 + hddUsedPercent = -1 + + if self.switchCPU: + cpu = psutil.cpu_percent() + + if self.switchRAM: + ram = psutil.virtual_memory() + ramTotal = ram.total + ramUsed = ram.used + ramUsedPercent = ram.percent + + if self.switchHDD: + hdd = psutil.disk_usage(self.whichHDD) + hddTotal = hdd.total + hddUsed = hdd.used + hddUsedPercent = hdd.percent + + getStatus = self.GPUInfo.getStatus() + + return { + 'cpu_utilization': cpu, + 'ram_total': ramTotal, + 'ram_used': ramUsed, + 'ram_used_percent': ramUsedPercent, + 'hdd_total': hddTotal, + 'hdd_used': hddUsed, + 'hdd_used_percent': hddUsedPercent, + 'device_type': getStatus['device_type'], + 'gpus': getStatus['gpus'], + } diff --git a/general/hdd.py b/general/hdd.py new file mode 100644 index 0000000..a34339e --- /dev/null +++ b/general/hdd.py @@ -0,0 +1,10 @@ +import psutil +from ..core import logger + +def getHDDsInfo(): + hdds = [] + logger.debug('Getting HDDs info...') + for partition in psutil.disk_partitions(): + hdds.append(partition.mountpoint) + + return hdds diff --git a/general/monitor.py b/general/monitor.py index 9eef5a1..e505d36 100644 --- a/general/monitor.py +++ b/general/monitor.py @@ -2,7 +2,7 @@ import asyncio import server import time import threading -from .stats import CStats +from .hardware import CHardwareInfo from ..core import logger @@ -13,11 +13,11 @@ class CMonitor: monitorThread = None threadController = threading.Event() rate = 0 - stats = None + hardwareInfo = None def __init__(self, rate=5, switchCPU=False, switchGPU=False, switchHDD=False, switchRAM=False, switchVRAM=False): self.rate = rate - self.stats = CStats(switchCPU, switchGPU, switchHDD, switchRAM, switchVRAM) + self.hardwareInfo = CHardwareInfo(switchCPU, switchGPU, switchHDD, switchRAM, switchVRAM) self.startMonitor() @@ -28,7 +28,7 @@ class CMonitor: def monitorLoop(self): while self.rate > 0 and not self.threadController.is_set(): - data = self.stats.buildStatsData() + data = self.hardwareInfo.getStatus() # print(data) asyncio.run(self.send_message(data)) time.sleep(self.rate) diff --git a/server/monitor.py b/server/monitor.py index b80ce75..995eefb 100644 --- a/server/monitor.py +++ b/server/monitor.py @@ -1,8 +1,7 @@ -import psutil from server import PromptServer from aiohttp import web from ..core import logger -from ..general.monitor import cmonitor +from ..general import cmonitor, getHDDsInfo, getGPUsInfo @PromptServer.instance.routes.patch("/crystools/monitor") async def newSettings(request): @@ -26,42 +25,42 @@ async def newSettings(request): if type(switchCPU) is not bool: raise Exception('switchCPU must be an boolean.') - cmonitor.stats.switchCPU = switchCPU + cmonitor.hardwareInfo.switchCPU = switchCPU if 'switchGPU' in settings is not None: switchGPU = settings['switchGPU'] if type(switchGPU) is not bool: raise Exception('switchGPU must be an boolean.') - cmonitor.stats.switchGPU = switchGPU + cmonitor.hardwareInfo.switchGPU = switchGPU if 'switchHDD' in settings is not None: switchHDD = settings['switchHDD'] if type(switchHDD) is not bool: raise Exception('switchHDD must be an boolean.') - cmonitor.stats.switchHDD = switchHDD + cmonitor.hardwareInfo.switchHDD = switchHDD if 'switchRAM' in settings is not None: switchRAM = settings['switchRAM'] if type(switchRAM) is not bool: raise Exception('switchRAM must be an boolean.') - cmonitor.stats.switchRAM = switchRAM + cmonitor.hardwareInfo.switchRAM = switchRAM if 'switchVRAM' in settings is not None: switchVRAM = settings['switchVRAM'] if type(switchVRAM) is not bool: raise Exception('switchVRAM must be an boolean.') - cmonitor.stats.switchVRAM = switchVRAM + cmonitor.hardwareInfo.switchVRAM = switchVRAM if 'whichHDD' in settings is not None: whichHDD = settings['whichHDD'] if type(whichHDD) is not str: raise Exception('whichHDD must be an string.') - cmonitor.stats.whichHDD = whichHDD + cmonitor.hardwareInfo.whichHDD = whichHDD return web.Response(status=200) @@ -92,14 +91,18 @@ async def monitorSwitch(request): @PromptServer.instance.routes.get("/crystools/monitor/HDD") -async def getHDDs(request): +def getHDDs(request): try: - hdds = [] + return web.json_response(getHDDsInfo()) + except Exception as e: + logger.error(e) + return web.Response(status=400, text=str(e)) - for partition in psutil.disk_partitions(): - hdds.append(partition.mountpoint) - return web.json_response(hdds) +@PromptServer.instance.routes.get("/crystools/monitor/GPU") +def getGPUs(request): + try: + return web.json_response(getGPUsInfo()) except Exception as e: logger.error(e) return web.Response(status=400, text=str(e)) diff --git a/web/monitor.js b/web/monitor.js index 5e44882..01be48b 100644 --- a/web/monitor.js +++ b/web/monitor.js @@ -296,25 +296,6 @@ class CrystoolsMonitor { }); }, }); - void this.getHDDsFromServer().then((data) => { - const which = app.ui.settings.getSettingValue(this.idWhichHDD, this.defaultWhichHDD); - app.ui.settings.addSetting({ - id: this.idWhichHDD, - name: this.menuPrefix + 'Partition to show (HDD)', - type: 'combo', - defaultValue: this.defaultWhichHDD, - options: (value) => data.map((m) => ({ - value: m, - text: m, - selected: !value ? m === which : m === value, - })), - onChange: async (value) => { - await this.updateServer({ - whichHDD: value, - }); - }, - }); - }); app.ui.settings.addSetting({ id: this.idInputRate, name: this.menuPrefix + 'Monitors refresh rate (in seconds) [menu]', @@ -387,6 +368,28 @@ class CrystoolsMonitor { } }, }); + void this.getHDDsFromServer().then((data) => { + const which = app.ui.settings.getSettingValue(this.idWhichHDD, this.defaultWhichHDD); + app.ui.settings.addSetting({ + id: this.idWhichHDD, + name: this.menuPrefix + 'Partition to show (HDD)', + type: 'combo', + defaultValue: this.defaultWhichHDD, + options: (value) => data.map((m) => ({ + value: m, + text: m, + selected: !value ? m === which : m === value, + })), + onChange: async (value) => { + await this.updateServer({ + whichHDD: value, + }); + }, + }); + }); + void this.getGPUsFromServer().then((data) => { + console.log('data', data); + }); } }); Object.defineProperty(this, "updateServer", { @@ -410,7 +413,23 @@ class CrystoolsMonitor { configurable: true, writable: true, value: async () => { - const resp = await api.fetchApi('/crystools/monitor/HDD', { + return this.getDataFromServer('HDD'); + } + }); + Object.defineProperty(this, "getGPUsFromServer", { + enumerable: true, + configurable: true, + writable: true, + value: async () => { + return this.getDataFromServer('GPU'); + } + }); + Object.defineProperty(this, "getDataFromServer", { + enumerable: true, + configurable: true, + writable: true, + value: async (what) => { + const resp = await api.fetchApi(`/crystools/monitor/${what}`, { method: 'GET', cache: 'no-store', }); diff --git a/web/monitor.ts b/web/monitor.ts index 30ffa2c..4a4aed7 100644 --- a/web/monitor.ts +++ b/web/monitor.ts @@ -120,28 +120,6 @@ class CrystoolsMonitor { }, }); - void this.getHDDsFromServer().then((data: string[]): void => { - const which = app.ui.settings.getSettingValue(this.idWhichHDD, this.defaultWhichHDD); - - app.ui.settings.addSetting({ - id: this.idWhichHDD, - name: this.menuPrefix + 'Partition to show (HDD)', - type: 'combo', - defaultValue: this.defaultWhichHDD, - options: (value: string) => - data.map((m) => ({ - value: m, - text: m, - selected: !value ? m === which : m === value, - })), - onChange: async(value: string) => { - await this.updateServer({ - whichHDD: value, - }); - }, - }); - }); - app.ui.settings.addSetting({ id: this.idInputRate, name: this.menuPrefix + 'Monitors refresh rate (in seconds) [menu]', @@ -218,6 +196,52 @@ class CrystoolsMonitor { } }, }); + + void this.getHDDsFromServer().then((data: string[]): void => { + const which = app.ui.settings.getSettingValue(this.idWhichHDD, this.defaultWhichHDD); + + app.ui.settings.addSetting({ + id: this.idWhichHDD, + name: this.menuPrefix + 'Partition to show (HDD)', + type: 'combo', + defaultValue: this.defaultWhichHDD, + options: (value: string) => + data.map((m) => ({ + value: m, + text: m, + selected: !value ? m === which : m === value, + })), + onChange: async(value: string) => { + await this.updateServer({ + whichHDD: value, + }); + }, + }); + }); + + + void this.getGPUsFromServer().then((data: string[]): void => { + // const which = app.ui.settings.getSettingValue(this.idWhichHDD, this.defaultWhichHDD); + console.log('data', data); + // app.ui.settings.addSetting({ + // id: this.idWhichHDD+2, + // name: this.menuPrefix + 'Partition to show (HDD)', + // type: 'combo', + // defaultValue: this.defaultWhichHDD, + // options: (value: string) => + // data.map((m) => ({ + // // value: m, + // // text: m, + // // selected: !value ? m === which : m === value, + // })), + // onChange: async(value: string) => { + // console.log('value', value); + // // await this.updateServer({ + // // whichHDD: value, + // // }); + // }, + // }); + }); }; updateServer = async(data: TStatsSettings): Promise => { @@ -233,7 +257,15 @@ class CrystoolsMonitor { }; getHDDsFromServer = async(): Promise => { - const resp = await api.fetchApi('/crystools/monitor/HDD', { + return this.getDataFromServer('HDD'); + }; + + getGPUsFromServer = async(): Promise => { + return this.getDataFromServer('GPU'); + }; + + getDataFromServer = async(what: string): Promise => { + const resp = await api.fetchApi(`/crystools/monitor/${what}`, { method: 'GET', cache: 'no-store', });