source: sasview/src/sas/qtgui/Perspectives/Fitting/GPUOptions.py @ 50bfab0

ESS_GUIESS_GUI_DocsESS_GUI_batch_fittingESS_GUI_bumps_abstractionESS_GUI_iss1116ESS_GUI_iss879ESS_GUI_iss959ESS_GUI_openclESS_GUI_orderingESS_GUI_sync_sascalc
Last change on this file since 50bfab0 was c7ebb37, checked in by Piotr Rozyczko <rozyczko@…>, 7 years ago

Allow SASView to run on the CPU if OpenCL doesn't find a platform.

  • Property mode set to 100644
File size: 7.8 KB
RevLine 
[06ce180]1# global
[a6cd8d1]2import os
3import sys
4import sasmodels
[ced1bff]5import json
6import platform
[f1f3e6a]7import webbrowser
[06ce180]8
[9863343]9import sas.qtgui.Utilities.GuiUtils as GuiUtils
[1543f0c]10from PyQt5 import QtGui, QtCore, QtWebKit, QtWidgets
[06ce180]11from sas.qtgui.Perspectives.Fitting.UI.GPUOptionsUI import Ui_GPUOptions
[ced1bff]12from sas.qtgui.Perspectives.Fitting.UI.GPUTestResultsUI import Ui_GPUTestResults
[06ce180]13
[14fa542]14try:
15    _fromUtf8 = QtCore.QString.fromUtf8
16except AttributeError:
17    def _fromUtf8(s):
18        return s
[06ce180]19
[14fa542]20try:
[1543f0c]21    _encoding = QtWidgets.QApplication.UnicodeUTF8
[14fa542]22    def _translate(context, text, disambig):
[1543f0c]23        return QtWidgets.QApplication.translate(context, text, disambig, _encoding)
[14fa542]24except AttributeError:
25    def _translate(context, text, disambig):
[1543f0c]26        return QtWidgets.QApplication.translate(context, text, disambig)
[06ce180]27
28
[1543f0c]29class GPUOptions(QtWidgets.QDialog, Ui_GPUOptions):
[06ce180]30    """
[37be27f]31    OpenCL Dialog to select the desired OpenCL driver
[06ce180]32    """
33
[a6cd8d1]34    clicked = False
35    sas_open_cl = None
36
[06ce180]37    def __init__(self, parent=None):
38        super(GPUOptions, self).__init__(parent)
[a6cd8d1]39        self.parent = parent
[06ce180]40        self.setupUi(self)
[a6cd8d1]41        self.addOpenCLOptions()
42        self.createLinks()
[06ce180]43
[a6cd8d1]44    def addOpenCLOptions(self):
45        """
46        Populate the window with a list of OpenCL options
47        """
[14fa542]48        # Get list of openCL options and add to GUI
[a6cd8d1]49        cl_tuple = _get_clinfo()
50        self.sas_open_cl = os.environ.get("SAS_OPENCL", "")
[14fa542]51        for title, descr in cl_tuple:
[c31d41e7]52            # Create an item for each openCL option
[1543f0c]53            check_box = QtWidgets.QCheckBox()
[37be27f]54            check_box.setObjectName(_fromUtf8(descr))
55            check_box.setText(_translate("GPUOptions", descr, None))
[c31d41e7]56            self.optionsLayout.addWidget(check_box)
[37be27f]57            if (descr == self.sas_open_cl) or (
58                            title == "None" and not self.clicked):
59                check_box.click()
[a6cd8d1]60                self.clicked = True
[1543f0c]61        self.openCLCheckBoxGroup.setMinimumWidth(self.optionsLayout.sizeHint().width()+10)
[37be27f]62
[a6cd8d1]63    def createLinks(self):
64        """
[37be27f]65        Link user interactions to function calls
[a6cd8d1]66        """
[9863343]67        self.testButton.clicked.connect(self.testButtonClicked)
68        self.helpButton.clicked.connect(self.helpButtonClicked)
[1543f0c]69        for item in self.openCLCheckBoxGroup.findChildren(QtWidgets.QCheckBox):
[9863343]70            item.clicked.connect(self.checked)
[a6cd8d1]71
72    def checked(self):
73        """
[37be27f]74        Only allow a single check box to be selected. Uncheck others.
[a6cd8d1]75        """
[1df1025]76        checked = None
[1543f0c]77        for box in self.openCLCheckBoxGroup.findChildren(QtWidgets.QCheckBox):
[1df1025]78            if box.isChecked() and (str(box.text()) == self.sas_open_cl or (
[37be27f]79                    str(box.text()) == "No OpenCL" and self.sas_open_cl == "")):
[a6cd8d1]80                box.setChecked(False)
[37be27f]81            elif box.isChecked():
[1df1025]82                checked = box
83        if hasattr(checked, "text"):
84            self.sas_open_cl = str(checked.text())
[a6cd8d1]85        else:
86            self.sas_open_cl = None
87
[0bb1397]88    def set_sas_open_cl(self):
[ced1bff]89        """
[37be27f]90        Set SAS_OPENCL value when tests run or OK button clicked
[a6cd8d1]91        """
[ced1bff]92        no_opencl_msg = False
93        if self.sas_open_cl:
94            os.environ["SAS_OPENCL"] = self.sas_open_cl
95            if self.sas_open_cl.lower() == "none":
96                no_opencl_msg = True
97        else:
98            if "SAS_OPENCL" in os.environ:
99                del os.environ["SAS_OPENCL"]
100        # Sasmodels kernelcl doesn't exist when initiated with None
101        if 'sasmodels.kernelcl' in sys.modules:
102            sasmodels.kernelcl.ENV = None
[1543f0c]103        from importlib import reload # assumed Python > 3.3
[ced1bff]104        reload(sasmodels.core)
105        return no_opencl_msg
106
107    def testButtonClicked(self):
[a6cd8d1]108        """
[ced1bff]109        Run sasmodels check from here and report results from
110        """
111
[0bb1397]112        no_opencl_msg = self.set_sas_open_cl()
[ced1bff]113
114        # Only import when tests are run
115        from sasmodels.model_test import model_tests
116
117        try:
118            from sasmodels.kernelcl import environment
119            env = environment()
120            clinfo = [(ctx.devices[0].platform.vendor,
121                       ctx.devices[0].platform.version,
122                       ctx.devices[0].vendor,
123                       ctx.devices[0].name,
124                       ctx.devices[0].version)
125                      for ctx in env.context]
126        except ImportError:
127            clinfo = None
128
129        failures = []
130        tests_completed = 0
131        for test in model_tests():
132            try:
133                test()
134            except Exception:
135                failures.append(test.description)
136
137            tests_completed += 1
138
139        info = {
140            'version': sasmodels.__version__,
141            'platform': platform.uname(),
142            'opencl': clinfo,
143            'failing tests': failures,
144        }
145
146        msg = str(tests_completed) + ' tests completed.\n'
147        if len(failures) > 0:
148            msg += str(len(failures)) + ' tests failed.\n'
149            msg += 'Failing tests: '
150            msg += json.dumps(info['failing tests'])
151            msg += "\n"
152        else:
153            msg += "All tests passed!\n"
154
155        msg += "\nPlatform Details:\n\n"
156        msg += "Sasmodels version: "
157        msg += info['version'] + "\n"
158        msg += "\nPlatform used: "
159        msg += json.dumps(info['platform']) + "\n"
160        if no_opencl_msg:
161            msg += "\nOpenCL driver: None"
162        else:
163            msg += "\nOpenCL driver: "
164            msg += json.dumps(info['opencl']) + "\n"
[9863343]165        GPUTestResults(self, msg)
[a6cd8d1]166
167    def helpButtonClicked(self):
168        """
169        Open the help menu when the help button is clicked
170        """
[9863343]171        help_location = GuiUtils.HELP_DIRECTORY_LOCATION
172        help_location += "/user/sasgui/perspectives/fitting/gpu_setup.html"
173        help_location += "#device-selection"
[f1f3e6a]174        # Test the system browser solution
175        webbrowser.open('file://' + os.path.realpath(help_location))
[a6cd8d1]176
177    def reject(self):
178        """
179        Close the window without modifying SAS_OPENCL
180        """
[c82fd8f]181        self.closeEvent(None)
182        self.parent.gpu_options_widget.open()
[a6cd8d1]183
184    def accept(self):
185        """
186        Close the window after modifying the SAS_OPENCL value
187        """
[0bb1397]188        self.set_sas_open_cl()
189        self.closeEvent(None)
[a6cd8d1]190
191    def closeEvent(self, event):
192        """
193        Overwrite QDialog close method to allow for custom widget close
194        """
[c82fd8f]195        self.close()
[0bb1397]196        self.parent.gpu_options_widget = GPUOptions(self.parent)
[a6cd8d1]197
198
[1543f0c]199class GPUTestResults(QtWidgets.QDialog, Ui_GPUTestResults):
[ced1bff]200    """
201    OpenCL Dialog to modify the OpenCL options
202    """
[9863343]203    def __init__(self, parent, msg):
[ced1bff]204        super(GPUTestResults, self).__init__(parent)
205        self.setupUi(self)
206        self.resultsText.setText(_translate("GPUTestResults", msg, None))
[1543f0c]207        #self.setFixedSize(self.size())
[ced1bff]208        self.open()
209
210
[a6cd8d1]211def _get_clinfo():
212    """
[37be27f]213    Read in information about available OpenCL infrastructure
[a6cd8d1]214    """
215    clinfo = []
[9863343]216    cl_platforms = []
[a6cd8d1]217    try:
218        import pyopencl as cl
[9863343]219        cl_platforms = cl.get_platforms()
[a6cd8d1]220    except ImportError:
221        print("pyopencl import failed. Using only CPU computations")
[c7ebb37]222    except cl.LogicError as e:
223        print(e.value)
[a6cd8d1]224
225    p_index = 0
[9863343]226    for cl_platform in cl_platforms:
[a6cd8d1]227        d_index = 0
[9863343]228        cl_platforms = cl_platform.get_devices()
229        for cl_platform in cl_platforms:
230            if len(cl_platforms) > 1 and len(cl_platforms) > 1:
[a6cd8d1]231                combined_index = ":".join([str(p_index), str(d_index)])
[9863343]232            elif len(cl_platforms) > 1:
[a6cd8d1]233                combined_index = str(p_index)
234            else:
235                combined_index = str(d_index)
[9863343]236            clinfo.append((combined_index, ":".join([cl_platform.name,
237                                                     cl_platform.name])))
[a6cd8d1]238            d_index += 1
239        p_index += 1
240
241    clinfo.append(("None", "No OpenCL"))
242    return clinfo
Note: See TracBrowser for help on using the repository browser.