source: sasview/src/sas/sasgui/perspectives/fitting/gpu_options.py @ 8b24bb8

Last change on this file since 8b24bb8 was 895703d, checked in by Paul Kienzle <pkienzle@…>, 6 years ago

clean out existing kernels when changing compute engine

  • Property mode set to 100644
File size: 10.7 KB
Line 
1'''
2Module provides dialog for setting SAS_OPENCL variable, which defines
3device choice for OpenCL calculation
4
5Created on Nov 29, 2016
6
7@author: wpotrzebowski
8'''
9
10import json
11import platform
12import logging
13import os
14import sys
15
16import wx
17
18try:
19    import pyopencl as cl
20except ImportError:
21    cl = None
22
23import sasmodels
24import sasmodels.model_test
25import sasmodels.sasview_model
26
27from sas.sasgui.guiframe.documentation_window import DocumentationWindow
28
29logger = logging.getLogger(__name__)
30
31
32
33class CustomMessageBox(wx.Dialog):
34    """
35    Custom message box for OpenCL results
36    """
37    def __init__(self, parent, msg, title):
38
39        wx.Dialog.__init__(self, parent, title=title)
40
41        self.static_box = wx.StaticBox(self, -1, "OpenCL test completed!")
42        self.boxsizer = wx.BoxSizer(orient=wx.VERTICAL)
43
44        self.text = wx.TextCtrl(self, -1, size=(500, 300),
45                                style=wx.TE_MULTILINE|wx.TE_READONLY)
46        self.text.SetValue(msg)
47        self.text.SetBackgroundColour(self.GetBackgroundColour())
48        self.text.SetFocus()
49        self.text.SetInsertionPoint(self.text.GetLastPosition())
50        self.boxsizer.Add(self.text, proportion=1, flag=wx.EXPAND)
51
52        self.fit_hsizer = wx.StaticBoxSizer(self.static_box, orient=wx.VERTICAL)
53        self.fit_hsizer.Add(self.boxsizer, 0, wx.ALL, 5)
54
55        self.vbox = wx.BoxSizer(wx.VERTICAL)
56        self.vbox.Add(self.fit_hsizer, 0, wx.ALL, 10)
57
58        self.message_text = wx.StaticText(self, -1, "If tests fail on OpenCL devices, "
59                                                    "please select No OpenCL option.\n\n"
60                                                    "In case of large number of failing tests, "
61                                                    "please consider sending\n"
62                                                    "above report to help@sasview.org.")
63
64        self.vbox.Add(self.message_text, 0, wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 10)
65
66        self.ok_btn = wx.Button(self, wx.ID_OK)
67
68        self.btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
69        self.btn_sizer.Add((10, 20), 1) # stretchable whitespace
70        self.btn_sizer.Add(self.ok_btn, 0)
71
72        self.vbox.Add(self.btn_sizer, 0, wx.EXPAND|wx.ALL, 10)
73
74        self.SetSizer(self.vbox)
75        self.vbox.Fit(self)
76
77        self.SetAutoLayout(True)
78        self.ShowModal()
79        self.Destroy()
80
81
82class GpuOptions(wx.Dialog):
83    """
84    "OpenCL options" Dialog Box
85
86    Provides dialog for setting SAS_OPENCL variable, which defines
87    device choice for OpenCL calculation
88
89    """
90
91    def __init__(self, *args, **kwds):
92
93        kwds["style"] = wx.DEFAULT_DIALOG_STYLE
94        wx.Dialog.__init__(self, *args, **kwds)
95
96        clinfo = self._get_clinfo()
97
98        self.panel1 = wx.Panel(self, -1)
99        static_box1 = wx.StaticBox(self.panel1, -1, "Available OpenCL Options:")
100
101        boxsizer = wx.BoxSizer(orient=wx.VERTICAL)
102        self.option_button = {}
103        self.buttons = []
104        #Check if SAS_OPENCL is already set as environment variable
105        self.sas_opencl = os.environ.get("SAS_OPENCL", "")
106
107        for clopt in clinfo:
108            button = wx.CheckBox(self.panel1, -1, label=clopt[1], name=clopt[1])
109
110            if clopt != "No OpenCL":
111                self.option_button[clopt[1]] = clopt[0]
112                if self.sas_opencl == clopt[0]:
113                    button.SetValue(1)
114            else:
115                self.option_button[clopt] = "None"
116                if self.sas_opencl.lower() == "none":
117                    button.SetValue(1)
118
119            self.Bind(wx.EVT_CHECKBOX, self.on_check, id=button.GetId())
120            self.buttons.append(button)
121            boxsizer.Add(button, 0, 0)
122
123        fit_hsizer = wx.StaticBoxSizer(static_box1, orient=wx.VERTICAL)
124        fit_hsizer.Add(boxsizer, 0, wx.ALL, 5)
125
126        self.panel1.SetSizer(fit_hsizer)
127
128        self.vbox = wx.BoxSizer(wx.VERTICAL)
129        self.vbox.Add(self.panel1, 0, wx.ALL, 10)
130
131        accept_btn = wx.Button(self, wx.ID_OK)
132        accept_btn.SetToolTipString("Accept new OpenCL settings. This will"
133                                    " override SAS_OPENCL variable if set")
134
135        help_id = wx.NewId()
136        help_btn = wx.Button(self, help_id, 'Help')
137        help_btn.SetToolTipString("Help on the GPU options")
138
139        reset_id = wx.NewId()
140        reset_btn = wx.Button(self, reset_id, 'Reset')
141        reset_btn.SetToolTipString("Restore initial settings")
142
143        test_id = wx.NewId()
144        test_btn = wx.Button(self, test_id, 'Test')
145        test_btn.SetToolTipString("Test if models compile on the given infrastructure")
146
147        self.Bind(wx.EVT_BUTTON, self.on_OK, accept_btn)
148        self.Bind(wx.EVT_BUTTON, self.on_test, test_btn)
149        self.Bind(wx.EVT_BUTTON, self.on_reset, reset_btn)
150        self.Bind(wx.EVT_BUTTON, self.on_help, help_btn)
151
152        test_text = wx.StaticText(self, -1, "WARNING: Running tests can take a few minutes!")
153        test_text2 = wx.StaticText(self, -1, "NOTE: No test will run if No OpenCL is checked")
154        test_text.SetForegroundColour(wx.RED)
155        self.vbox.Add(test_text2, 0, wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 10)
156        self.vbox.Add(test_text, 0, wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 10)
157
158        btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
159        btn_sizer.Add((10, 20), 1) # stretchable whitespace
160        btn_sizer.Add(accept_btn, 0)
161        btn_sizer.Add((10, 20), 0) # non-stretchable whitespace
162        btn_sizer.Add(test_btn, 0)
163        btn_sizer.Add((10, 20), 0) # non-stretchable whitespace
164        btn_sizer.Add(reset_btn, 0)
165        btn_sizer.Add((10, 20), 0) # non-stretchable whitespace
166        btn_sizer.Add(help_btn, 0)
167
168        # Add the button sizer to the main sizer.
169        self.vbox.Add(btn_sizer, 0, wx.EXPAND|wx.ALL, 10)
170
171        self.SetSizer(self.vbox)
172        self.vbox.Fit(self)
173        self.SetTitle("OpenCL options")
174        self.Centre()
175
176    def _get_clinfo(self):
177        """
178        Reading in information about available OpenCL infrastructure
179        :return:
180        """
181        clinfo = []
182        platforms = []
183
184        if cl is None:
185            logger.warn("Unable to import the pyopencl package.  It may not "
186                        "have been installed.  If you wish to use OpenCL, try "
187                        "running pip install --user pyopencl")
188        else:
189            try:
190                platforms = cl.get_platforms()
191            except cl.LogicError as err:
192                logger.warn("Unable to fetch the OpenCL platforms.  This likely "
193                            "means that the opencl drivers for your system are "
194                            "not installed.")
195                logger.warn(err)
196
197        p_index = 0
198        for platform in platforms:
199            d_index = 0
200            devices = platform.get_devices()
201            for device in devices:
202                if len(devices) > 1 and len(platforms) > 1:
203                    combined_index = ":".join([str(p_index), str(d_index)])
204                elif len(platforms) > 1:
205                    combined_index = str(p_index)
206                else:
207                    combined_index = str(d_index)
208                clinfo.append((combined_index, ":".join([platform.name, device.name])))
209                d_index += 1
210            p_index += 1
211
212        clinfo.append(("None", "No OpenCL"))
213        return clinfo
214
215    def on_check(self, event):
216        """
217        Action triggered when box is selected
218        :param event:
219        :return:
220        """
221        selected_button = event.GetEventObject()
222        for btn in self.buttons:
223            if btn != selected_button:
224                btn.SetValue(0)
225        if selected_button.GetValue():
226            self.sas_opencl = self.option_button[selected_button.Name]
227        else:
228            self.sas_opencl = None
229
230    def on_OK(self, event):
231        """
232        Close window on accpetance
233        """
234
235        #If statement added to handle Reset
236        if self.sas_opencl:
237            os.environ["SAS_OPENCL"] = self.sas_opencl
238        else:
239            if "SAS_OPENCL" in os.environ:
240                del os.environ["SAS_OPENCL"]
241        sasmodels.sasview_model.reset_environment()
242        event.Skip()
243
244    def on_reset(self, event):
245        """
246        Resets selected values
247        """
248        for btn in self.buttons:
249            btn.SetValue(0)
250
251        self.sas_opencl = None
252
253    def on_test(self, event):
254        """
255        Run sasmodels check from here and report results from
256        """
257        #The same block of code as for OK but it is needed if we want to have
258        #active response to Test button
259        no_opencl_msg = False
260        if self.sas_opencl:
261            os.environ["SAS_OPENCL"] = self.sas_opencl
262            if self.sas_opencl.lower() == "none":
263                no_opencl_msg = True
264        else:
265            if "SAS_OPENCL" in os.environ:
266                del os.environ["SAS_OPENCL"]
267        sasmodels.sasview_model.reset_environment()
268
269        try:
270            env = sasmodels.kernelcl.environment()
271            clinfo = [(ctx.devices[0].platform.vendor,
272                       ctx.devices[0].platform.version,
273                       ctx.devices[0].vendor,
274                       ctx.devices[0].name,
275                       ctx.devices[0].version)
276                      for ctx in env.context]
277        except Exception:
278            clinfo = None
279
280        failures = []
281        tests_completed = 0
282        for test in sasmodels.model_test.model_tests():
283            try:
284                test()
285            except Exception:
286                failures.append(test.description)
287
288            tests_completed += 1
289
290        info = {
291            'version':  sasmodels.__version__,
292            'platform': platform.uname(),
293            'opencl': clinfo,
294            'failing tests': failures,
295        }
296
297        msg_info = 'OpenCL tests results'
298
299        msg = str(tests_completed)+' tests completed.\n'
300        if len(failures) > 0:
301            msg += str(len(failures))+' tests failed.\n'
302            msg += 'Failing tests: '
303            msg += json.dumps(info['failing tests'])
304            msg += "\n"
305        else:
306            msg += "All tests passed!\n"
307
308        msg += "\nPlatform Details:\n\n"
309        msg += "Sasmodels version: "
310        msg += info['version']+"\n"
311        msg += "\nPlatform used: "
312        msg += json.dumps(info['platform'])+"\n"
313        if no_opencl_msg:
314            msg += "\nOpenCL driver: None"
315        else:
316            msg += "\nOpenCL driver: "
317            msg += json.dumps(info['opencl'])+"\n"
318
319        CustomMessageBox(self.panel1, msg, msg_info)
320
321    def on_help(self, event):
322        """
323        Provide help on opencl options.
324        """
325        TreeLocation = "user/sasgui/perspectives/fitting/gpu_setup.html"
326        anchor = "#device-selection"
327        DocumentationWindow(self, -1,
328                            TreeLocation, anchor, "OpenCL Options Help")
Note: See TracBrowser for help on using the repository browser.