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

Last change on this file since 1b9a367 was 73cbeec, checked in by Piotr Rozyczko <piotr.rozyczko@…>, 8 years ago

Opencl dialog (#29)

Merged OpenCL dialog prototype branch

  • Support to read available OpenCL infrastructure
  • Added support for SAS_OPENCL in sasview
  • Calling CL devices from get_devices rather than create some context
  • Calling more than on platform
  • Changing clinfo setup
  • Code cleanup
  • lint fixes
  • Added better exception handling
  • Fixed help button accidently disabled with the previous commit
  • Setting dialog to unmodal
  • Setting 0 values at setup
  • Switched to checkbox, beacuase all of them can be unset during initialization
  • Switiching to more appropriate HELP button
  • Code clean-up after review by PR
  • Interactive response to SAS_OPENCL enviroment
  • Added handling for platform names
  • Corrected warning
  • Handling for PYOPENCL_CTX for multiple platforms added
  • Bug fixed
  • Support for more than one platform and one device
  • Minor code cleanup
  • Added test button - currently outputs to console
  • Towards saving in comnfig file
  • Added settings reading from custom config file
  • Writting to settings file
  • Added message dialog for testing results
  • Writting to configuration file at the end of session
  • Setting NoOpenCL as defult
  • Setting proper CL env even when initiated from None
  • Adding back-compatibility support if SAS_OPENCL is not set in config_file
  • Added warning about lenght of tests
  • Return more reasonable test messages
  • Font changed so it looks better on Windows
  • Minor code cleanup
  • Code cleanup
  • Added focus om text box to make Windows working
  • and fixing line
  • making conditional check for kernelcl module
  • Minor code changes to make pylint happy
  • Changes to code after code review by PR
  • Removing panel wx element that prevented mouse scrolling
  • Property mode set to 100644
File size: 10.4 KB
RevLine 
[73cbeec]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.static_box = wx.StaticBox(self, -1, "OpenCL test completed!")
28        self.boxsizer = wx.BoxSizer(orient=wx.VERTICAL)
29
30        self.text = wx.TextCtrl(self, -1, size=(500, 300),
31                                style=wx.TE_MULTILINE|wx.TE_READONLY)
32        self.text.SetValue(msg)
33        self.text.SetBackgroundColour(self.GetBackgroundColour())
34        self.text.SetFocus()
35        self.text.SetInsertionPoint(self.text.GetLastPosition())
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.vbox = wx.BoxSizer(wx.VERTICAL)
42        self.vbox.Add(self.fit_hsizer, 0, wx.ALL, 10)
43
44        self.message_text = wx.StaticText(self, -1, "If tests fail on OpenCL devices, "
45                                                    "please select No OpenCL option.\n\n"
46                                                    "In case of large number of failing tests, "
47                                                    "please consider sending\n"
48                                                    "above report to help@sasview.org.")
49
50        self.vbox.Add(self.message_text, 0, wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 10)
51
52        self.ok_btn = wx.Button(self, wx.ID_OK)
53
54        self.btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
55        self.btn_sizer.Add((10, 20), 1) # stretchable whitespace
56        self.btn_sizer.Add(self.ok_btn, 0)
57
58        self.vbox.Add(self.btn_sizer, 0, wx.EXPAND|wx.ALL, 10)
59
60        self.SetSizer(self.vbox)
61        self.vbox.Fit(self)
62
63        self.SetAutoLayout(True)
64        self.ShowModal()
65        self.Destroy()
66
67
68class GpuOptions(wx.Dialog):
69    """
70    "OpenCL options" Dialog Box
71
72    Provides dialog for setting SAS_OPENCL variable, which defines
73    device choice for OpenCL calculation
74
75    """
76
77    def __init__(self, *args, **kwds):
78
79        kwds["style"] = wx.DEFAULT_DIALOG_STYLE
80        wx.Dialog.__init__(self, *args, **kwds)
81
82        clinfo = self._get_clinfo()
83
84        self.panel1 = wx.Panel(self, -1)
85        static_box1 = wx.StaticBox(self.panel1, -1, "Available OpenCL Options:")
86
87        boxsizer = wx.BoxSizer(orient=wx.VERTICAL)
88        self.option_button = {}
89        self.buttons = []
90        #Check if SAS_OPENCL is already set as enviromental variable
91        self.sas_opencl = os.environ.get("SAS_OPENCL", "")
92
93        for clopt in clinfo:
94            button = wx.CheckBox(self.panel1, -1, label=clopt[1], name=clopt[1])
95
96            if clopt != "No OpenCL":
97                self.option_button[clopt[1]] = clopt[0]
98                if self.sas_opencl == clopt[0]:
99                    button.SetValue(1)
100            else:
101                self.option_button[clopt] = "None"
102                if self.sas_opencl.lower() == "none":
103                    button.SetValue(1)
104
105            self.Bind(wx.EVT_CHECKBOX, self.on_check, id=button.GetId())
106            self.buttons.append(button)
107            boxsizer.Add(button, 0, 0)
108
109        fit_hsizer = wx.StaticBoxSizer(static_box1, orient=wx.VERTICAL)
110        fit_hsizer.Add(boxsizer, 0, wx.ALL, 5)
111
112        self.panel1.SetSizer(fit_hsizer)
113
114        self.vbox = wx.BoxSizer(wx.VERTICAL)
115        self.vbox.Add(self.panel1, 0, wx.ALL, 10)
116
117        accept_btn = wx.Button(self, wx.ID_OK)
118        accept_btn.SetToolTipString("Accept new OpenCL settings. This will"
119                                    " override SAS_OPENCL variable if set")
120
121        help_id = wx.NewId()
122        help_btn = wx.Button(self, help_id, 'Help')
123        help_btn.SetToolTipString("Help on the GPU options")
124
125        reset_id = wx.NewId()
126        reset_btn = wx.Button(self, reset_id, 'Reset')
127        reset_btn.SetToolTipString("Restore initial settings")
128
129        test_id = wx.NewId()
130        test_btn = wx.Button(self, test_id, 'Test')
131        test_btn.SetToolTipString("Test if models compile on the given infrastructure")
132
133        self.Bind(wx.EVT_BUTTON, self.on_OK, accept_btn)
134        self.Bind(wx.EVT_BUTTON, self.on_test, test_btn)
135        self.Bind(wx.EVT_BUTTON, self.on_reset, reset_btn)
136        self.Bind(wx.EVT_BUTTON, self.on_help, help_btn)
137
138        test_text = wx.StaticText(self, -1, "WARNING: Running tests can take a few minutes!")
139        self.vbox.Add(test_text, 0, wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 10)
140
141        btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
142        btn_sizer.Add((10, 20), 1) # stretchable whitespace
143        btn_sizer.Add(accept_btn, 0)
144        btn_sizer.Add((10, 20), 0) # non-stretchable whitespace
145        btn_sizer.Add(test_btn, 0)
146        btn_sizer.Add((10, 20), 0) # non-stretchable whitespace
147        btn_sizer.Add(reset_btn, 0)
148        btn_sizer.Add((10, 20), 0) # non-stretchable whitespace
149        btn_sizer.Add(help_btn, 0)
150
151        # Add the button sizer to the main sizer.
152        self.vbox.Add(btn_sizer, 0, wx.EXPAND|wx.ALL, 10)
153
154        self.SetSizer(self.vbox)
155        self.vbox.Fit(self)
156        self.SetTitle("OpenCL options")
157        self.Centre()
158
159    def _get_clinfo(self):
160        """
161        Reading in information about available OpenCL infrastructure
162        :return:
163        """
164        clinfo = []
165        platforms = []
166        try:
167            import pyopencl as cl
168            platforms = cl.get_platforms()
169        except ImportError:
170            warnings.warn("pyopencl import failed. Using only CPU computations")
171
172        p_index = 0
173        for platform in platforms:
174            d_index = 0
175            devices = platform.get_devices()
176            for device in devices:
177                if len(devices) > 1 and len(platforms) > 1:
178                    combined_index = ":".join([str(p_index), str(d_index)])
179                elif len(platforms) > 1:
180                    combined_index = str(p_index)
181                else:
182                    combined_index = str(d_index)
183                clinfo.append((combined_index, ":".join([platform.name, device.name])))
184                d_index += 1
185            p_index += 1
186
187        clinfo.append(("None", "No OpenCL"))
188        return clinfo
189
190    def on_check(self, event):
191        """
192        Action triggered when box is selected
193        :param event:
194        :return:
195        """
196        selected_button = event.GetEventObject()
197        for btn in self.buttons:
198            if btn != selected_button:
199                btn.SetValue(0)
200        if selected_button.GetValue():
201            self.sas_opencl = self.option_button[selected_button.Name]
202        else:
203            self.sas_opencl = None
204
205    def on_OK(self, event):
206        """
207        Close window on accpetance
208        """
209
210        #If statement added to handle Reset
211        if self.sas_opencl:
212            os.environ["SAS_OPENCL"] = self.sas_opencl
213        else:
214            if "SAS_OPENCL" in os.environ:
215                del os.environ["SAS_OPENCL"]
216
217        #Sasmodels kernelcl doesn't exist when initiated with None
218        if 'sasmodels.kernelcl' in sys.modules:
219            sasmodels.kernelcl.ENV = None
220
221        reload(sasmodels.core)
222        event.Skip()
223
224    def on_reset(self, event):
225        """
226        Resets selected values
227        """
228        for btn in self.buttons:
229            btn.SetValue(0)
230
231        self.sas_opencl = None
232
233    def on_test(self, event):
234        """
235        Run sasmodels check from here and report results from
236        """
237        import json
238        import platform
239        #import sasmodels
240
241        #The same block of code as for OK but it is needed if we want to have
242        #active response to Test button
243        no_opencl_msg = False
244        if self.sas_opencl:
245            os.environ["SAS_OPENCL"] = self.sas_opencl
246            if self.sas_opencl.lower() == "none":
247                no_opencl_msg = True
248        else:
249            if "SAS_OPENCL" in os.environ:
250                del os.environ["SAS_OPENCL"]
251
252        #Sasmodels kernelcl doesn't exist when initiated with None
253        if 'sasmodels.kernelcl' in sys.modules:
254            sasmodels.kernelcl.ENV = None
255
256
257        #Need to reload sasmodels.core module to account SAS_OPENCL = "None"
258        reload(sasmodels.core)
259
260
261        from sasmodels.model_test import model_tests
262
263        try:
264            from sasmodels.kernelcl import environment
265            env = environment()
266            clinfo = [(ctx.devices[0].platform.vendor,
267                       ctx.devices[0].platform.version,
268                       ctx.devices[0].vendor,
269                       ctx.devices[0].name,
270                       ctx.devices[0].version)
271                      for ctx in env.context]
272        except ImportError:
273            clinfo = None
274
275        failures = []
276        tests_completed = 0
277        for test in model_tests():
278            try:
279                test()
280            except Exception:
281                failures.append(test.description)
282
283            tests_completed += 1
284
285        info = {
286            'version':  sasmodels.__version__,
287            'platform': platform.uname(),
288            'opencl': clinfo,
289            'failing tests': failures,
290        }
291
292        msg_info = 'OpenCL tests results'
293
294        msg = str(tests_completed)+' tests completed.\n'
295        if len(failures) > 0:
296            msg += str(len(failures))+' tests failed.\n'
297            msg += 'Failing tests: '
298            msg += json.dumps(info['failing tests'])
299            msg += "\n"
300        else:
301            msg += "All tests passed!\n"
302
303        msg += "\nPlatform Details:\n\n"
304        msg += "Sasmodels version: "
305        msg += info['version']+"\n"
306        msg += "\nPlatform used: "
307        msg += json.dumps(info['platform'])+"\n"
308        if no_opencl_msg:
309            msg += "\nOpenCL driver: None"
310        else:
311            msg += "\nOpenCL driver: "
312            msg += json.dumps(info['opencl'])+"\n"
313
314        CustomMessageBox(self.panel1, msg, msg_info)
315
316    def on_help(self, event):
317        """
318        Provide help on opencl options.
319        """
320        TreeLocation = "user/gpu_computations.html"
321        anchor = "#device-selection"
322        DocumentationWindow(self, -1,
323                            TreeLocation, anchor, "OpenCL Options Help")
Note: See TracBrowser for help on using the repository browser.