source: sasview/src/sas/sasgui/perspectives/fitting/gpu_options.py @ 388aefb

magnetic_scattrelease-4.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249unittest-saveload
Last change on this file since 388aefb was 388aefb, checked in by butler, 10 months 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.