def autotune(self, I, E, O):

        autotune_key = " ".join(self.autotune_key)
        #print "autotune: ", self.autotune_key

        start, stop = self.lib.get_events()

        # Only need to do warmup once
        if not self.lib.warmup:
            self.lib.warmup = True
            # warmup  with a conservative set of params
            self.init(self.params, autotune=(self.GYS, 1, 1))
            self.bind_params(I, E, O, 1.0)
            self.execute(repeat=self.warmup, unbind=False)

        # we want at least this many blocks
        block_slots = _get_sm_count()
        # loops for given size of N
        loopsN = max(self.params[0] // 4, 1)
        # don't bother with internal mode for N>4
        modes = (0,1) if self.params[0] <= 4 else (1,)

        gys = float(self.GYS)
        gxs = float(self.GYS)
        small_set = gys * gxs <= 512

        results = []
        sys.stdout.write("Autotune " + str(self))
        progress = 0
        for threshold in (True, False):
            for external in modes:
                for strideY in range(1, self.GYS+1):
                    for strideX in range(1, self.GXS+1):
                        if progress % 32 == 0:
                            sys.stdout.write('.')
                            sys.stdout.flush()
                        progress += 1

                        # CRSK copies in determ mode
                        outputs = strideY * strideX

                        # minimal occupancy filter
                        blocks = self.blocksCK * strideY * strideX
                        # gemm loop size filter
                        depth = (gys / strideY) * (gxs / strideX) * loopsN

                        filters = outputs <= 768 and  blocks >= block_slots and depth >= 32.0

                        # In case we filter out all settings, run though the loops again
                        # this time looking only at settings that didn't pass.
                        if small_set or (threshold and filters) or (not threshold and not filters):

                            settings = (strideY, strideX, external)
                            #print settings

                            self.init(self.params, autotune=settings)
                            self.bind_params(I, E, O, 1.0)
                            start.record(stream=self.lib.stream)
                            self.execute(repeat=2, unbind=False)
                            stop.record(stream=self.lib.stream)
                            stop.synchronize()
                            msecs = 2.0 / stop.time_since(start)
                            results.append((msecs, settings))

                        # else:
                        #     print strideY, strideX, external, blocks, round(depth,1)

            # if we got any results, no need to disable the filter
            if len(results) > 0:
                break
        sys.stdout.write('\n')

        results.sort()
        settings = results[0][1]
        # for res in results[0:10]:
        #     print res

        autotune_db = shelve.open(self.autotune_db_file)
        autotune_db[autotune_key] = settings

        # add a copy if this layer has small strides
        # deterministic vs non-determ should make no speed difference here
        if settings[0] * settings[1] <= 8:
            self.autotune_key[2] = str(1 - int(self.autotune_key[2]))
            autotune_key = " ".join(self.autotune_key)
            autotune_db[autotune_key] = settings

        autotune_db.close()

        self.init(self.params, autotune=settings)
dataset/ETHPy150Open NervanaSystems/neon/neon/backends/winograd_conv.py/UpdateWinograd.autotune/swapped operands of `/`