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
RevLine 
[f78c7d2]1'''
[8f02f7f]2Module provides dialog for setting SAS_OPENCL variable, which defines
3device choice for OpenCL calculation
4
[16c1297]5Created on Nov 29, 2016
[f78c7d2]6
[16c1297]7@author: wpotrzebowski
[f78c7d2]8'''
9
[6a569b3]10import os
[4320104]11import sys
[6a569b3]12import warnings
[f78c7d2]13import wx
[1b061a31]14import sasmodels
[16c1297]15from sas.sasgui.guiframe.documentation_window import DocumentationWindow
[e2c0939]16
[16c1297]17
[25594ca]18
19class CustomMessageBox(wx.Dialog):
[65d1d04]20    """
21    Custom message box for OpenCL results
22    """
[25594ca]23    def __init__(self, parent, msg, title):
[2a1b92eb]24
[25594ca]25        wx.Dialog.__init__(self, parent, title=title)
[2a1b92eb]26
[55b935e]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)
[2a1b92eb]30
[55b935e]31        self.text = wx.TextCtrl(self, -1, size=(500, 400),
[65d1d04]32                                style=wx.TE_MULTILINE|wx.TE_READONLY)
[55b935e]33        self.text.SetValue(msg)
34        self.text.SetBackgroundColour(self.GetBackgroundColour())
[755ecb0]35        self.text.SetFocus()
[55b935e]36        self.boxsizer.Add(self.text, proportion=1, flag=wx.EXPAND)
[2a1b92eb]37
[55b935e]38        self.fit_hsizer = wx.StaticBoxSizer(self.static_box, orient=wx.VERTICAL)
39        self.fit_hsizer.Add(self.boxsizer, 0, wx.ALL, 5)
[2a1b92eb]40
[55b935e]41        self.panel.SetSizer(self.fit_hsizer)
[2a1b92eb]42
[55b935e]43        self.vbox = wx.BoxSizer(wx.VERTICAL)
44        self.vbox.Add(self.panel, 0, wx.ALL, 10)
[2a1b92eb]45
[65d1d04]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.")
[0c9204a]51
[55b935e]52        self.vbox.Add(self.message_text, 0, wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 10)
[0c9204a]53
[55b935e]54        self.ok_btn = wx.Button(self, wx.ID_OK)
[2a1b92eb]55
[55b935e]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)
[2a1b92eb]59
[55b935e]60        self.vbox.Add(self.btn_sizer, 0, wx.EXPAND|wx.ALL, 10)
[2a1b92eb]61
[55b935e]62        self.SetSizer(self.vbox)
63        self.vbox.Fit(self)
[2a1b92eb]64
[755ecb0]65        self.SetAutoLayout(True)
[25594ca]66        self.ShowModal()
67        self.Destroy()
68
69
[f78c7d2]70class GpuOptions(wx.Dialog):
71    """
[8f02f7f]72    "OpenCL options" Dialog Box
[f78c7d2]73
[8f02f7f]74    Provides dialog for setting SAS_OPENCL variable, which defines
75    device choice for OpenCL calculation
[f78c7d2]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
[16c1297]84        clinfo = self._get_clinfo()
[9fdf302]85
[f78c7d2]86        self.panel1 = wx.Panel(self, -1)
[16c1297]87        static_box1 = wx.StaticBox(self.panel1, -1, "Available OpenCL Options:")
[f78c7d2]88
[9fdf302]89        boxsizer = wx.BoxSizer(orient=wx.VERTICAL)
[c2cb772]90        self.option_button = {}
[bacc04b]91        self.buttons = []
[6af411b]92        #Check if SAS_OPENCL is already set as enviromental variable
[65d1d04]93        self.sas_opencl = os.environ.get("SAS_OPENCL", "")
[92583049]94
[ebaaf05]95        for clopt in clinfo:
96            button = wx.CheckBox(self.panel1, -1, label=clopt[1], name=clopt[1])
[71ac835]97
[a9279cc]98            if clopt != "No OpenCL":
[ebaaf05]99                self.option_button[clopt[1]] = clopt[0]
100                if self.sas_opencl == clopt[0]:
[71ac835]101                    button.SetValue(1)
[c2cb772]102            else:
[a9279cc]103                self.option_button[clopt] = "None"
[62243ae]104                if self.sas_opencl.lower() == "none":
[71ac835]105                    button.SetValue(1)
106
[8f02f7f]107            self.Bind(wx.EVT_CHECKBOX, self.on_check, id=button.GetId())
[bacc04b]108            self.buttons.append(button)
[9fdf302]109            boxsizer.Add(button, 0, 0)
[f78c7d2]110
111        fit_hsizer = wx.StaticBoxSizer(static_box1, orient=wx.VERTICAL)
[9fdf302]112        fit_hsizer.Add(boxsizer, 0, wx.ALL, 5)
[f78c7d2]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)
[c2cb772]118
119        accept_btn = wx.Button(self, wx.ID_OK)
[71ac835]120        accept_btn.SetToolTipString("Accept new OpenCL settings. This will"
[92583049]121                                    " override SAS_OPENCL variable if set")
[c2cb772]122
[075c460]123        help_id = wx.NewId()
124        help_btn = wx.Button(self, help_id, 'Help')
[c2cb772]125        help_btn.SetToolTipString("Help on the GPU options")
126
[71ac835]127        reset_id = wx.NewId()
128        reset_btn = wx.Button(self, reset_id, 'Reset')
129        reset_btn.SetToolTipString("Restore initial settings")
130
[bd55e15]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
[8f02f7f]135        self.Bind(wx.EVT_BUTTON, self.on_OK, accept_btn)
[bd55e15]136        self.Bind(wx.EVT_BUTTON, self.on_test, test_btn)
[71ac835]137        self.Bind(wx.EVT_BUTTON, self.on_reset, reset_btn)
[6a569b3]138        self.Bind(wx.EVT_BUTTON, self.on_help, help_btn)
[c2cb772]139
[65d1d04]140        test_text = wx.StaticText(self, -1, "WARNING: Running tests can take a few minutes!")
[f370ea07]141        self.vbox.Add(test_text, 0, wx.LEFT|wx.EXPAND|wx.ADJUST_MINSIZE, 10)
[bd55e15]142
[c2cb772]143        btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
[6a569b3]144        btn_sizer.Add((10, 20), 1) # stretchable whitespace
[c2cb772]145        btn_sizer.Add(accept_btn, 0)
[6a569b3]146        btn_sizer.Add((10, 20), 0) # non-stretchable whitespace
[bd55e15]147        btn_sizer.Add(test_btn, 0)
148        btn_sizer.Add((10, 20), 0) # non-stretchable whitespace
[71ac835]149        btn_sizer.Add(reset_btn, 0)
150        btn_sizer.Add((10, 20), 0) # non-stretchable whitespace
[c2cb772]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)
[7feb69d]158        self.SetTitle("OpenCL options")
[c2cb772]159        self.Centre()
[f78c7d2]160
[16c1297]161    def _get_clinfo(self):
[7feb69d]162        """
163        Reading in information about available OpenCL infrastructure
164        :return:
165        """
[95f0cbb]166        clinfo = []
[1b061a31]167        platforms = []
[16c1297]168        try:
169            import pyopencl as cl
[ebaaf05]170            platforms = cl.get_platforms()
[6a569b3]171        except ImportError:
[4139147]172            warnings.warn("pyopencl import failed. Using only CPU computations")
[95f0cbb]173
[1b061a31]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
[65d1d04]189        clinfo.append(("None", "No OpenCL"))
[16c1297]190        return clinfo
[f78c7d2]191
[8f02f7f]192    def on_check(self, event):
[6a569b3]193        """
[2a1b92eb]194        Action triggered when box is selected
[6a569b3]195        :param event:
196        :return:
197        """
[bacc04b]198        selected_button = event.GetEventObject()
199        for btn in self.buttons:
200            if btn != selected_button:
201                btn.SetValue(0)
[7feb69d]202        if selected_button.GetValue():
203            self.sas_opencl = self.option_button[selected_button.Name]
204        else:
205            self.sas_opencl = None
[c2cb772]206
[8f02f7f]207    def on_OK(self, event):
[c2cb772]208        """
[9fdf302]209        Close window on accpetance
[c2cb772]210        """
[1b061a31]211
[71ac835]212        #If statement added to handle Reset
213        if self.sas_opencl:
214            os.environ["SAS_OPENCL"] = self.sas_opencl
[62243ae]215        else:
[71ac835]216            if "SAS_OPENCL" in os.environ:
[65d1d04]217                del os.environ["SAS_OPENCL"]
[e2c0939]218
219        #Sasmodels kernelcl doesn't exist when initiated with None
[4320104]220        if 'sasmodels.kernelcl' in sys.modules:
[e2c0939]221            sasmodels.kernelcl.ENV = None
222
[8f02f7f]223        reload(sasmodels.core)
[c2cb772]224        event.Skip()
225
[71ac835]226    def on_reset(self, event):
227        """
[1b061a31]228        Resets selected values
[71ac835]229        """
230        for btn in self.buttons:
231            btn.SetValue(0)
[25594ca]232
[65d1d04]233        self.sas_opencl = None
[71ac835]234
[bd55e15]235    def on_test(self, event):
236        """
237        Run sasmodels check from here and report results from
238        """
239        import json
240        import platform
[1b061a31]241        #import sasmodels
[0c9204a]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
[51cc0eb]245        no_opencl_msg = False
[0c9204a]246        if self.sas_opencl:
247            os.environ["SAS_OPENCL"] = self.sas_opencl
[51cc0eb]248            if self.sas_opencl.lower() == "none":
249                no_opencl_msg = True
[0c9204a]250        else:
251            if "SAS_OPENCL" in os.environ:
[65d1d04]252                del os.environ["SAS_OPENCL"]
[0c9204a]253
254        #Sasmodels kernelcl doesn't exist when initiated with None
[4320104]255        if 'sasmodels.kernelcl' in sys.modules:
[0c9204a]256            sasmodels.kernelcl.ENV = None
[4320104]257
[0c9204a]258
259        #Need to reload sasmodels.core module to account SAS_OPENCL = "None"
260        reload(sasmodels.core)
261
262
[bd55e15]263        from sasmodels.model_test import model_tests
[25594ca]264
[bd55e15]265        try:
266            from sasmodels.kernelcl import environment
267            env = environment()
268            clinfo = [(ctx.devices[0].platform.vendor,
[65d1d04]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]
[bd55e15]274        except ImportError:
275            clinfo = None
276
277        failures = []
[0c9204a]278        tests_completed = 0
[bd55e15]279        for test in model_tests():
280            try:
281                test()
282            except Exception:
283                failures.append(test.description)
284
[0c9204a]285            tests_completed += 1
286
[bd55e15]287        info = {
288            'version':  sasmodels.__version__,
289            'platform': platform.uname(),
290            'opencl': clinfo,
291            'failing tests': failures,
292        }
[25594ca]293
[0c9204a]294        msg_info = 'OpenCL tests results'
[2a1b92eb]295
[0c9204a]296        msg = str(tests_completed)+' tests completed.\n'
[25594ca]297        if len(failures) > 0:
[0c9204a]298            msg += str(len(failures))+' tests failed.\n'
299            msg += 'Failing tests: '
[25594ca]300            msg += json.dumps(info['failing tests'])
[65d1d04]301            msg += "\n"
[25594ca]302        else:
[65d1d04]303            msg += "All tests passed!\n"
[2a1b92eb]304
[65d1d04]305        msg += "\nPlatform Details:\n\n"
[2a1b92eb]306        msg += "Sasmodels version: "
307        msg += info['version']+"\n"
308        msg += "\nPlatform used: "
309        msg += json.dumps(info['platform'])+"\n"
[51cc0eb]310        if no_opencl_msg:
[0c9204a]311            msg += "\nOpenCL driver: None"
312        else:
313            msg += "\nOpenCL driver: "
314            msg += json.dumps(info['opencl'])+"\n"
[25594ca]315
316        CustomMessageBox(self.panel1, msg, msg_info)
[bd55e15]317
[c027106e]318    def on_help(self, event):
[c2cb772]319        """
[9fdf302]320        Provide help on opencl options.
[c2cb772]321        """
[6a569b3]322        TreeLocation = "user/gpu_computations.html"
323        anchor = "#device-selection"
[16c1297]324        DocumentationWindow(self, -1,
[6a569b3]325                            TreeLocation, anchor, "OpenCL Options Help")
Note: See TracBrowser for help on using the repository browser.