source: sasview/src/sas/sasgui/perspectives/fitting/gpu_options.py @ 1b061a31

Last change on this file since 1b061a31 was 1b061a31, checked in by wojciech, 7 years ago

Changes to code after code review by PR

  • Property mode set to 100644
File size: 10.4 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 os
11import sys
12import warnings
13import wx
14import sasmodels
15from sas.sasgui.guiframe.documentation_window import DocumentationWindow
16
17
18
19class CustomMessageBox(wx.Dialog):
20    """
21    Custom message box for OpenCL results
22    """
23    def __init__(self, parent, msg, title):
24
25        wx.Dialog.__init__(self, parent, title=title)
26
27        self.panel = wx.Panel(self, -1)
28        self.static_box = wx.StaticBox(self.panel, -1, "OpenCL test completed!")
29        self.boxsizer = wx.BoxSizer(orient=wx.VERTICAL)
30
31        self.text = wx.TextCtrl(self, -1, size=(500, 400),
32                                style=wx.TE_MULTILINE|wx.TE_READONLY)
33        self.text.SetValue(msg)
34        self.text.SetBackgroundColour(self.GetBackgroundColour())
35        self.text.SetFocus()
36        self.boxsizer.Add(self.text, proportion=1, flag=wx.EXPAND)
37
38        self.fit_hsizer = wx.StaticBoxSizer(self.static_box, orient=wx.VERTICAL)
39        self.fit_hsizer.Add(self.boxsizer, 0, wx.ALL, 5)
40
41        self.panel.SetSizer(self.fit_hsizer)
42
43        self.vbox = wx.BoxSizer(wx.VERTICAL)
44        self.vbox.Add(self.panel, 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 enviromental 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        self.vbox.Add(test_text, 0, wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 10)
142
143        btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
144        btn_sizer.Add((10, 20), 1) # stretchable whitespace
145        btn_sizer.Add(accept_btn, 0)
146        btn_sizer.Add((10, 20), 0) # non-stretchable whitespace
147        btn_sizer.Add(test_btn, 0)
148        btn_sizer.Add((10, 20), 0) # non-stretchable whitespace
149        btn_sizer.Add(reset_btn, 0)
150        btn_sizer.Add((10, 20), 0) # non-stretchable whitespace
151        btn_sizer.Add(help_btn, 0)
152
153        # Add the button sizer to the main sizer.
154        self.vbox.Add(btn_sizer, 0, wx.EXPAND|wx.ALL, 10)
155
156        self.SetSizer(self.vbox)
157        self.vbox.Fit(self)
158        self.SetTitle("OpenCL options")
159        self.Centre()
160
161    def _get_clinfo(self):
162        """
163        Reading in information about available OpenCL infrastructure
164        :return:
165        """
166        clinfo = []
167        platforms = []
168        try:
169            import pyopencl as cl
170            platforms = cl.get_platforms()
171        except ImportError:
172            warnings.warn("pyopencl import failed. Using only CPU computations")
173
174        p_index = 0
175        for platform in platforms:
176            d_index = 0
177            devices = platform.get_devices()
178            for device in devices:
179                if len(devices) > 1 and len(platforms) > 1:
180                    combined_index = ":".join([str(p_index), str(d_index)])
181                elif len(platforms) > 1:
182                    combined_index = str(p_index)
183                else:
184                    combined_index = str(d_index)
185                clinfo.append((combined_index, ":".join([platform.name, device.name])))
186                d_index += 1
187            p_index += 1
188
189        clinfo.append(("None", "No OpenCL"))
190        return clinfo
191
192    def on_check(self, event):
193        """
194        Action triggered when box is selected
195        :param event:
196        :return:
197        """
198        selected_button = event.GetEventObject()
199        for btn in self.buttons:
200            if btn != selected_button:
201                btn.SetValue(0)
202        if selected_button.GetValue():
203            self.sas_opencl = self.option_button[selected_button.Name]
204        else:
205            self.sas_opencl = None
206
207    def on_OK(self, event):
208        """
209        Close window on accpetance
210        """
211
212        #If statement added to handle Reset
213        if self.sas_opencl:
214            os.environ["SAS_OPENCL"] = self.sas_opencl
215        else:
216            if "SAS_OPENCL" in os.environ:
217                del os.environ["SAS_OPENCL"]
218
219        #Sasmodels kernelcl doesn't exist when initiated with None
220        if 'sasmodels.kernelcl' in sys.modules:
221            sasmodels.kernelcl.ENV = None
222
223        reload(sasmodels.core)
224        event.Skip()
225
226    def on_reset(self, event):
227        """
228        Resets selected values
229        """
230        for btn in self.buttons:
231            btn.SetValue(0)
232
233        self.sas_opencl = None
234
235    def on_test(self, event):
236        """
237        Run sasmodels check from here and report results from
238        """
239        import json
240        import platform
241        #import sasmodels
242
243        #The same block of code as for OK but it is needed if we want to have
244        #active response to Test button
245        no_opencl_msg = False
246        if self.sas_opencl:
247            os.environ["SAS_OPENCL"] = self.sas_opencl
248            if self.sas_opencl.lower() == "none":
249                no_opencl_msg = True
250        else:
251            if "SAS_OPENCL" in os.environ:
252                del os.environ["SAS_OPENCL"]
253
254        #Sasmodels kernelcl doesn't exist when initiated with None
255        if 'sasmodels.kernelcl' in sys.modules:
256            sasmodels.kernelcl.ENV = None
257
258
259        #Need to reload sasmodels.core module to account SAS_OPENCL = "None"
260        reload(sasmodels.core)
261
262
263        from sasmodels.model_test import model_tests
264
265        try:
266            from sasmodels.kernelcl import environment
267            env = environment()
268            clinfo = [(ctx.devices[0].platform.vendor,
269                       ctx.devices[0].platform.version,
270                       ctx.devices[0].vendor,
271                       ctx.devices[0].name,
272                       ctx.devices[0].version)
273                      for ctx in env.context]
274        except ImportError:
275            clinfo = None
276
277        failures = []
278        tests_completed = 0
279        for test in model_tests():
280            try:
281                test()
282            except Exception:
283                failures.append(test.description)
284
285            tests_completed += 1
286
287        info = {
288            'version':  sasmodels.__version__,
289            'platform': platform.uname(),
290            'opencl': clinfo,
291            'failing tests': failures,
292        }
293
294        msg_info = 'OpenCL tests results'
295
296        msg = str(tests_completed)+' tests completed.\n'
297        if len(failures) > 0:
298            msg += str(len(failures))+' tests failed.\n'
299            msg += 'Failing tests: '
300            msg += json.dumps(info['failing tests'])
301            msg += "\n"
302        else:
303            msg += "All tests passed!\n"
304
305        msg += "\nPlatform Details:\n\n"
306        msg += "Sasmodels version: "
307        msg += info['version']+"\n"
308        msg += "\nPlatform used: "
309        msg += json.dumps(info['platform'])+"\n"
310        if no_opencl_msg:
311            msg += "\nOpenCL driver: None"
312        else:
313            msg += "\nOpenCL driver: "
314            msg += json.dumps(info['opencl'])+"\n"
315
316        CustomMessageBox(self.panel1, msg, msg_info)
317
318    def on_help(self, event):
319        """
320        Provide help on opencl options.
321        """
322        TreeLocation = "user/gpu_computations.html"
323        anchor = "#device-selection"
324        DocumentationWindow(self, -1,
325                            TreeLocation, anchor, "OpenCL Options Help")
Note: See TracBrowser for help on using the repository browser.