source: sasview/src/sas/sasgui/perspectives/fitting/gpu_options.py @ 23ff8d5

Last change on this file since 23ff8d5 was 388aefb, checked in by butler, 6 years ago

Add warning to OpenCL dialog

Add note that "No OpenCL" will not run tests and put WARNING of it
taking a few minutes to run tests in red Addresses #1131

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