-
-
Notifications
You must be signed in to change notification settings - Fork 134
/
diagnostics.py
325 lines (288 loc) · 15 KB
/
diagnostics.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
try:
import platform
import subprocess
import logging
from importlib_metadata import distributions
import torch
import os # Import the os module
import re
import sys
import glob
import site
import textwrap
import torch
import packaging.version
import packaging.specifiers
from packaging.specifiers import SpecifierSet
from packaging.specifiers import SpecifierSet
from packaging.version import parse as parse_version
from pathlib import Path
except ImportError as e:
print(f"\033[91mError importing module: {e}\033[0m\n")
print("\033[94mPlease ensure you started the Text-generation-webUI Python environment with either\033[0m")
print("\033[92mcmd_linux.sh\033[0m, \033[92mcmd_windows.bat\033[0m, \033[92mcmd_macos.sh\033[0m, or \033[92mcmd_wsl.bat\033[0m")
print("\033[94mfrom the text-generation-webui directory, and then try running the diagnostics again.\033[0m")
exit(1)
this_dir = Path(__file__).parent
try:
import psutil
except ImportError:
print("psutil not found. Installing...")
subprocess.run(['pip', 'install', 'psutil'])
import psutil
def get_requirements_file():
this_dir = Path(__file__).parent # Assuming 'this_dir' is defined as the script's directory
requirements_dir = this_dir / 'system' / 'requirements'
requirements_files = list(requirements_dir.glob('requirements*.txt')) # Using pathlib for globbing
if not requirements_files:
print("\033[91mNo requirements files found.\033[0m")
return None
print("\033[94m\nSelect a requirements file to check against (or press Enter for default 'requirements.txt'):\033[0m\n")
for i, file_path in enumerate(requirements_files, start=1):
print(f" {i}. {file_path.name}") # Only print the filename
choice = input("\nEnter the number of your choice: ")
try:
choice = int(choice) - 1
return str(requirements_files[choice]) # Return the full path as a string
except (ValueError, IndexError):
return str(requirements_dir / "requirements.txt") # Return the default path as a string
# Set up logging with filemode='w'
logging.basicConfig(filename='diagnostics.log',
filemode='w',
level=logging.INFO,
format='%(message)s') # Custom format
# Function to get GPU information using subprocess
def get_gpu_info():
try:
result = subprocess.run(['nvidia-smi'], stdout=subprocess.PIPE, text=True)
return result.stdout
except FileNotFoundError:
return "NVIDIA GPU information not available"
def get_cpu_info():
cpu_info = {
'physical_cores': psutil.cpu_count(logical=False),
'total_cores': psutil.cpu_count(logical=True),
'max_frequency': psutil.cpu_freq().max
}
return cpu_info
def get_disk_info():
disk_info = []
partitions = psutil.disk_partitions()
for p in partitions:
usage = psutil.disk_usage(p.mountpoint)
disk_info.append(f" Drive: {p.device} | Total: {usage.total / (1024 ** 3):.2f} GB | Used: {usage.used / (1024 ** 3):.2f} GB | Free: {usage.free / (1024 ** 3):.2f} GB | Type: {p.fstype}")
return disk_info
# Function to check if a port is in use
def is_port_in_use(port):
for conn in psutil.net_connections():
if conn.laddr.port == port:
return True
return False
def satisfies_wildcard(installed_version, required_version):
if '*' in required_version:
required_parts = required_version.split('.')
installed_parts = installed_version.split('.')
for req, inst in zip(required_parts, installed_parts):
if req != '*' and req != inst:
return False
return True
return False
def test_cuda():
cuda_available = torch.cuda.is_available()
if cuda_available:
try:
# Attempt to create a tensor on GPU
torch.tensor([1.0, 2.0]).cuda()
return "Success - CUDA is available and working."
except Exception as e:
return f"Fail - CUDA is available but not working. Error: {e}"
else:
return "Fail - CUDA is not available."
def find_files_in_path_with_wildcard(pattern):
# Get the site-packages directory of the current Python environment
site_packages_path = site.getsitepackages()
found_paths = []
# Adjust the sub-directory based on the operating system
sub_directory = "nvidia/cublas"
if platform.system() == "Linux":
sub_directory = os.path.join(sub_directory, "lib")
else:
sub_directory = os.path.join(sub_directory, "bin")
# Iterate over each site-packages directory (there can be more than one)
for directory in site_packages_path:
# Construct the search directory path
search_directory = os.path.join(directory, sub_directory)
# Use glob to find all files matching the pattern in this directory
for file_path in glob.glob(os.path.join(search_directory, pattern)):
if os.path.isfile(file_path): # Ensure it's a file
found_paths.append(file_path)
return found_paths
# Function to log and print system information
def log_system_info():
# System information
os_version = platform.system() + " " + platform.version()
# Get CUDA_HOME environment variable
cuda_home = os.environ.get('CUDA_HOME', 'N/A')
gpu_info = get_gpu_info()
# Python environment information
python_version = platform.python_version()
# Torch version
torch_version = torch.__version__
cuda_test_result = test_cuda()
cpu_info = get_cpu_info()
disk_info = get_disk_info()
# System RAM using psutil
try:
virtual_memory = psutil.virtual_memory()
total_ram = f"{virtual_memory.total / (1024 ** 3):.2f} GB"
available_ram = f"{virtual_memory.available / (1024 ** 3):.2f} GB"
system_ram = f"{available_ram} available out of {total_ram} total"
except NameError:
print("psutil is not installed. Unable to check system RAM.")
system_ram = "N/A"
# Port check (if psutil is available)
port_status = "N/A"
if 'psutil' in globals():
port_to_check = 7851
if is_port_in_use(port_to_check):
port_status = f"Port {port_to_check} is in use."
else:
port_status = f"Port {port_to_check} is available."
# Package versions using importlib_metadata
package_versions = {d.metadata['Name']: d.version for d in distributions()}
# Python environment information
python_executable = sys.executable
python_version_info = sys.version_info
python_virtual_env = os.environ.get('VIRTUAL_ENV', 'N/A')
# Conda environment information
conda_env = os.environ.get('CONDA_DEFAULT_ENV', 'N/A')
# Get Path environment information
search_path = sys.path
path_env = os.environ.get('PATH', 'N/A')
# Check for cublas
file_name = 'cublas64_11.*' if platform.system() == "Windows" else 'libcublas.so.11*'
found_paths = find_files_in_path_with_wildcard(file_name)
# Compare with requirements file
requirements_file = get_requirements_file()
if requirements_file:
required_packages = {}
installed_packages = {}
try:
with open(requirements_file, 'r') as req_file:
requirements = [line.strip() for line in req_file]
for req in requirements:
# Use regular expression to parse package name and version
match = re.match(r'([^\s>=]+)\s*([>=<]+)\s*([^,]+)', req)
if match:
package_name, operator, version_spec = match.groups()
installed_version = package_versions.get(package_name, 'Not installed')
if installed_version != 'Not installed':
required_packages[package_name] = (operator, version_spec)
installed_packages[package_name] = installed_version
except FileNotFoundError:
print(f"\n{requirements_file} not found. Skipping version checks.")
logging.info(f"NOTE {requirements_file} not found. Skipping version checks.")
# Log and print information
logging.info(f"OPERATING SYSTEM:")
logging.info(f" OS Version: {os_version}")
logging.info(f" Note: Windows 11 will list as build is 10.x.22xxx")
logging.info(f"\nHARDWARE ENVIRONMENT:")
logging.info(f" CPU: Physical Cores: {cpu_info['physical_cores']}, Total Cores: {cpu_info['total_cores']}, Max Frequency: {cpu_info['max_frequency']} MHz")
logging.info(f" System RAM: {system_ram}")
logging.info(f"\nGPU INFORMATION:{gpu_info}")
logging.info("DISK INFORMATION:")
for disk in disk_info:
logging.info(disk)
logging.info("\nNETWORK PORT:")
logging.info(f" Port Status: {port_status}")
logging.info("\nCUDA:")
logging.info(f" CUDA Working: {cuda_test_result}")
logging.info(f" CUDA_HOME: {cuda_home}")
if found_paths:
logging.info(f" Cublas64_11 Path: {', '.join(found_paths)}")
else:
logging.info(f" Cublas64_11 Path: Not found in any search path directories.")
logging.info("\nPYTHON & PYTORCH:")
logging.info(f" Torch Version: {torch_version}")
logging.info(f" Python Version: {platform.python_version()}")
logging.info(f" Python Version Info: {python_version_info}")
logging.info(f" Python Executable: {python_executable}")
logging.info(f" Python Virtual Environment: {python_virtual_env} (Should be N/A when in Text-generation-webui Conda Python environment)")
logging.info(f" Conda Environment: {conda_env}")
logging.info("\nPython Search Path:")
for path in search_path:
logging.info(f" {path}")
logging.info("\nOS SEARCHPATH ENVIRONMENT:")
for path in path_env.split(';'):
logging.info(f" {path}")
if required_packages: # Check if the dictionary is not empty
logging.info("\nPACKAGE VERSIONS vs REQUIREMENTS FILE:")
max_package_length = max(len(package) for package in required_packages.keys())
for package_name, (operator, required_version) in required_packages.items():
installed_version = installed_packages.get(package_name, 'Not installed')
logging.info(f" {package_name.ljust(max_package_length)} Required: {operator} {required_version.ljust(12)} Installed: {installed_version}")
logging.info("\nPYTHON PACKAGES:")
for package, version in package_versions.items():
logging.info(f" {package}>= {version}")
# Print to screen
print(f"\n\033[94mOS Version:\033[0m \033[92m{os_version}\033[0m")
print(f"\033[94mOS Ver note:\033[0m \033[92m(Windows 11 will say build is 10.x.22xxx)\033[0m")
print(f"\033[94mSystem RAM:\033[0m \033[92m{system_ram}\033[0m")
for disk in disk_info:
print(f"\033[94mDisk:\033[0m \033[92m{disk}\033[0m")
print(f"\033[94m\nGPU Information:\033[0m {gpu_info}")
print(f"\033[94mPort Status:\033[0m \033[92m{port_status}\033[0m\n")
if "Fail" in cuda_test_result:
print(f"\033[91mCUDA Working:\033[0m \033[91m{cuda_test_result}\033[0m")
else:
print(f"\033[94mCUDA Working:\033[0m \033[92m{cuda_test_result}\033[0m")
print(f"\033[94mCUDA_HOME:\033[0m \033[92m{cuda_home}\033[0m")
if found_paths:
print(f"\033[94mCublas64_11 Path:\033[0m \033[92m{', '.join(found_paths)}\033[0m")
else:
print(f"\033[94mCublas64_11 Path:\033[0m \033[91mNot found in any search path directories.\033[0m")
print(f"\033[94m\nTorch Version:\033[0m \033[92m{torch_version}\033[0m")
print(f"\033[94mPython Version:\033[0m \033[92m{platform.python_version()}\033[0m")
print(f"\033[94mPython Executable:\033[0m \033[92m{python_executable}\033[0m")
print(f"\033[94mConda Environment:\033[0m \033[92m{conda_env}\033[0m")
print(f"\n\033[94mPython Search Path:\033[0m")
for path in search_path:
print(f" {path}")
if required_packages: # Check if the dictionary is not empty
print("\033[94m\nRequirements file package comparison:\033[0m")
max_package_length = max(len(package) for package in required_packages.keys())
for package_name, (operator, required_version) in required_packages.items():
installed_version = installed_packages.get(package_name, 'Not installed')
# Exclude build information (e.g., +cu118) before creating the SpecifierSet
required_version_no_build = required_version.split("+")[0]
if '*' in required_version:
condition_met = satisfies_wildcard(installed_version, required_version)
else:
# Compare versions using packaging.version
required_specifier = SpecifierSet(f"{operator}{required_version_no_build}")
installed_version = parse_version(installed_version)
condition_met = installed_version in required_specifier
color_required = "\033[92m" if condition_met else "\033[91m"
color_installed = "\033[92m" if condition_met else "\033[91m"
# Print colored output
print(f" {package_name.ljust(max_package_length)} Required: {color_required}{operator} {required_version.ljust(12)}\033[0m Installed: {color_installed}{installed_version}\033[0m")
print("\nOn Nvidia Graphics cards machines, if your \033[92mInstalled\033[0m version of \033[92mTorch\033[0m and \033[92mTorchaudio\033[0m does")
print("not have \033[92m+cu118\033[0m (Cuda 11.8) or \033[92m+cu121\033[0m (Cuda 12.1) listed after them, you do not have CUDA")
print("installed for Torch or Torchaudio in this Python environment. This will cause you problems")
print("with \033[94mAllTalk\033[0m and \033[94mFinetuning.\033[0m You may have to 'pip install' a new version of torch and")
print("torchaudio, using '\033[94m--upgrade --force-reinstall\033[0m' with the correct version of PyTorch for\033[0m")
print("your Python environment.\033[0m")
print("\033[94m\nRequirements file specifier meanings:\033[0m")
explanation = textwrap.dedent("""
== Exact version != Any version except < Less than
<= Less than or equal to > Greater than >= Greater than or equal to
~ Compatible release ; Environment marker AND Logical AND
OR Logical OR
""")
print(explanation.strip())
print("")
print(f"\033[94mDiagnostic log created:\033[0m \033[92mdiagnostics.log. \033[94mA brief summary of results is displayed above on\033[0m")
print(f"\033[94mscreen. Please see the log file for more detail.\033[0m")
print(f"\033[94m\nPlease upload the log file with any support ticket.\033[0m")
if __name__ == "__main__":
log_system_info()