1# ########################################################################
2# Copyright 2013 Advanced Micro Devices, Inc.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15# ########################################################################
16
17import sys
18import argparse
19import subprocess
20import itertools
21import re#gex
22import os
23import math
24from threading import Timer, Thread
25import thread, time
26from platform import system
27import numpy as np
28
29from datetime import datetime
30
31import errorHandler
32from fftPerformanceTesting import *
33from performanceUtility import timeout, log, generate235Radices
34
35IAM = 'FFT'
36TIMOUT_VAL = 900  #In seconds
37
38devicevalues = ['g', 'c']
39layoutvalues = ['cp', 'ci']
40placevalues = ['in', 'out']
41precisionvalues = ['single', 'double']
42libraryvalues = ['clFFT','cuFFT']
43pow10 = '1-9,10-90:10,100-900:100,1000-9000:1000,10000-90000:10000,100000-900000:100000,1000000-9000000:1000000'
44
45parser = argparse.ArgumentParser(description='Measure performance of the clFFT library')
46parser.add_argument('--device',
47    dest='device', default='g',
48    help='device(s) to run on; may be a comma-delimited list. choices are ' + str(devicevalues) + '. (default gpu)')
49parser.add_argument('-b', '--batchsize',
50    dest='batchSize', default='1',
51    help='number of FFTs to perform with one invocation of the client. the special value \'adapt\' may be used to adjust the batch size on a per-transform basis to the maximum problem size possible on the device. (default 1)'.format(pow10))
52parser.add_argument('-a', '--adaptivemax',
53    dest='constProbSize', default='-1',
54    help='Max problem size that you want to maintain across the invocations of client with different lengths. This is adaptive and adjusts itself automtically.'.format(pow10))
55parser.add_argument('-x', '--lengthx',
56    dest='lengthx', default='1',
57    help='length(s) of x to test; must be factors of 1, 2, 3, or 5 with clFFT; may be a range or a comma-delimited list. e.g., 16-128 or 1200 or 16,2048-32768 (default 1)')
58parser.add_argument('-y', '--lengthy',
59    dest='lengthy', default='1',
60    help='length(s) of y to test; must be factors of 1, 2, 3, or 5 with clFFT; may be a range or a comma-delimited list. e.g., 16-128 or 1200 or 16,32768 (default 1)')
61parser.add_argument('-z', '--lengthz',
62    dest='lengthz', default='1',
63    help='length(s) of z to test; must be factors of 1, 2, 3, or 5 with clFFT; may be a range or a comma-delimited list. e.g., 16-128 or 1200 or 16,32768 (default 1)')
64parser.add_argument('-reps',
65    dest='reps', default='10',
66    help='Number of repetitions (default 10)')
67parser.add_argument('-prime_factor', '--prime_factor',
68    dest='prime_factor', default='2',
69    help='only test the prime factors within the specified range of lengthx/y/z. Select from 2,3,5, and 7. Example: -prime_factor 2,3')
70parser.add_argument('-test_count', '--test_count',
71    dest='test_count', default='100',
72    help='Number of tests to perform')
73parser.add_argument('--problemsize',
74    dest='problemsize', default=None)
75#    help='additional problems of a set size. may be used in addition to lengthx/y/z. each indicated problem size will be added to the list of FFTs to perform. should be entered in AxBxC:D format. A, B, and C indicate the sizes of the X, Y, and Z dimensions (respectively). D is the batch size. All values except the length of X are optional. may enter multiple in a comma-delimited list. e.g., 2x2x2:32768 or 256x256:100,512x512:256')
76parser.add_argument('-i', '--inputlayout',
77    dest='inputlayout', default='1',
78    help=' 1. interleaved (default) 2. planar  3. hermitian interleaved 4. hermitian planar  5. real' )
79parser.add_argument('-o', '--outputlayout',
80    dest='outputlayout', default='1',
81    help=' 1. interleaved (default) 2. planar  3. hermitian interleaved 4. hermitian planar  5. real' )
82parser.add_argument('--placeness',
83    dest='placeness', default='in',
84    help='Choices are ' + str(placevalues) + '. in = in place, out = out of place (default in)')
85parser.add_argument('-r', '--precision',
86    dest='precision', default='single',
87    help='Choices are ' + str(precisionvalues) + '. (default single)')
88parser.add_argument('--library',
89    dest='library', default='clFFT', choices=libraryvalues,
90    help='indicates the library to use for testing on this run')
91parser.add_argument('--label',
92    dest='label', default=None,
93    help='a label to be associated with all transforms performed in this run. if LABEL includes any spaces, it must be in \"double quotes\". note that the label is not saved to an .ini file. e.g., --label cayman may indicate that a test was performed on a cayman card or --label \"Windows 32\" may indicate that the test was performed on Windows 32')
94#parser.add_argument('--createini',
95#    dest='createIniFilename', default=None,
96#    help='create an .ini file with the given name that saves the other parameters given at the command line, then quit. e.g., \'measureperformance.py -x 2048 --createini my_favorite_setup.ini\' will create an .ini file that will save the configuration for a 2048-datapoint 1D FFT.')
97parser.add_argument('--ini',
98    dest='iniFilename', default=None,
99    help='use the parameters in the named .ini file instead of the command line parameters.')
100parser.add_argument('--tablefile',
101    dest='tableOutputFilename', default=None,
102    help='save the results to a plaintext table with the file name indicated. this can be used with plotPerformance.py to generate graphs of the data (default: table prints to screen)')
103parser.add_argument('--prefix',
104    dest='prefix', default='./',
105    help='Path where the library client is located (default current directory)')
106
107args = parser.parse_args()
108
109label = str(args.label)
110
111subprocess.call('mkdir perfLog', shell = True)
112logfile = os.path.join('perfLog', (label+'-'+'fftMeasurePerfLog.txt'))
113
114def printLog(txt):
115    print txt
116    log(logfile, txt)
117
118printLog("=========================MEASURE PERFORMANCE START===========================")
119printLog("Process id of Measure Performance:"+str(os.getpid()))
120
121currCommandProcess = None
122
123
124printLog('Executing measure performance for label: '+str(label))
125
126
127#This function is defunct now
128@timeout(1, "fileName") # timeout is 5 minutes, 5*60 = 300 secs
129def checkTimeOutPut2(args):
130    global currCommandProcess
131    #ret = subprocess.check_output(args, stderr=subprocess.STDOUT)
132    #return ret
133    currCommandProcess = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
134    printLog("Curr Command Process id = "+str(currCommandProcess.pid))
135    ret = currCommandProcess.communicate()
136    if(ret[0] == None or ret[0] == ''):
137        errCode = currCommandProcess.poll()
138        raise subprocess.CalledProcessError(errCode, args, output=ret[1])
139    return ret[0]
140
141
142#Spawns a separate thread to execute the library command and wait for that thread to complete
143#This wait is of 900 seconds (15 minutes). If still the thread is alive then we kill the thread
144def checkTimeOutPut(args):
145    t = None
146    global currCommandProcess
147    global stde
148    global stdo
149    stde = None
150    stdo = None
151    def executeCommand():
152        global currCommandProcess
153        global stdo
154        global stde
155        try:
156            stdo, stde = currCommandProcess.communicate()
157            printLog('stdout:\n'+str(stdo))
158            printLog('stderr:\n'+str(stde))
159        except:
160            printLog("ERROR: UNKNOWN Exception - +checkWinTimeOutPut()::executeCommand()")
161
162    currCommandProcess = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,shell=True)
163    thread = Thread(target=executeCommand)
164    thread.start()
165    thread.join(TIMOUT_VAL) #wait for the thread to complete
166    if thread.is_alive():
167        printLog('ERROR: Killing the process - terminating thread because it is taking too much of time to execute')
168        currCommandProcess.kill()
169        printLog('ERROR: Timed out exception')
170        raise errorHandler.ApplicationException(__file__, errorHandler.TIME_OUT)
171    if stdo == "" or stdo==None:
172        errCode = currCommandProcess.poll()
173        printLog('ERROR: @@@@@Raising Called processor exception')
174        raise subprocess.CalledProcessError(errCode, args, output=stde)
175    return stdo
176
177
178
179
180
181# don't try to create and use an .ini file at the same time (it will open a portal through which demons will emerge)
182#if args.iniFilename and args.createIniFilename:
183#    printLog('ERROR: --ini and --createini are mutually exclusive. Please choose only one.')
184#    quit()
185
186#read in .ini parameters if --ini is used
187#if args.iniFilename != None:
188#    if not os.path.isfile(args.iniFilename):
189#        printLog("No file with the name \'{}\' exists. Please indicate another filename.".format(args.iniFilename))
190#        quit()
191#
192#    ini = open(args.iniFilename, 'r')
193#    iniContents = ini.read()
194#    iniContents = iniContents.split(';')
195#    for i in range(0,len(iniContents)):
196#        line = iniContents.pop()
197#        line = line.partition(' ')
198#        parameter = line[0]
199#        value = line[2]
200#        value = value.replace('\'','').replace('[','').replace(']','').replace(' ','')
201#        print"value= ",value
202#
203#        if parameter == 'batchSize':
204#            args.batchSize = value
205#        elif parameter == 'constProbSize':
206#            args.constProbSize = value
207#        elif parameter == 'lengthx':
208#            args.lengthx = value
209#        elif parameter == 'reps':
210#            args.reps = value
211#        elif parameter == 'prime_factor':
212#            args.prime_factor = value
213#        elif parameter == 'test_count':
214#            args.test_count = value
215#        elif parameter == 'lengthy':
216#            args.lengthy = value
217#        elif parameter == 'lengthz':
218#            args.lengthz = value
219#        elif parameter == 'problemsize':
220#            args.problemsize = value
221#        elif parameter == 'device':
222#            args.device = value
223#        elif parameter == 'inputlayout':
224#            args.inputlayout = value
225#        elif parameter == 'outputlayout':
226#            args.outputlayout = value
227#        elif parameter == 'placeness':
228#            args.placeness = value
229#        elif parameter == 'precision':
230#            args.precision = value
231#        else:
232#            printLog('{} corrupted. Please re-create a .ini file with the --createini flag.'.format(args.iniFilename))
233#            #quit()
234
235#create ini file if requested
236#if args.createIniFilename != None:
237#    printLog('Creating Ini files')
238#    if os.path.isfile(args.createIniFilename):
239#        printLog('A file with the name \'{}\' already exists. Please delete the file or choose another name.'.format(args.createIniFilename))
240#        quit()
241#    printLog('Creating Ini file:'+args.createIniFilename+'\n')
242#    ini = open(args.createIniFilename, 'w')
243#    ini.write('batchSize {} ;'.format(args.batchSize))
244#    ini.write('constProbSize {} ;'.format(args.constProbSize))
245#    ini.write('lengthx {} ;'.format(args.lengthx))
246#    ini.write('lengthy {} ;'.format(args.lengthy))
247#    ini.write('lengthz {} ;'.format(args.lengthz))
248#    ini.write('prime_factor {} ;'.format(args.prime_factor))
249#    ini.write('test_count {} ;'.format(args.test_count))
250#    ini.write('reps {} ;'.format(args.reps))
251#    ini.write('problemsize {} ;'.format(args.problemsize))
252#    ini.write('device {} ;'.format(args.device))
253#    ini.write('inputlayout {} ;'.format(args.inputlayout))
254#    ini.write('outputlayout {} ;'.format(args.outputlayout))
255#    ini.write('placeness {} ;'.format(args.placeness))
256#    ini.write('precision {} ;'.format(args.precision))
257#    printLog('Created Ini file:'+args.createIniFilename+'\n')
258#    printLog("=========================MEASURE PERFORMANCE START===========================\n")
259#    quit()
260#
261
262#turn pow10 into its range list
263if args.batchSize.count('pow10'):
264    args.batchSize = pow10
265
266#split up comma-delimited lists
267args.batchSize = args.batchSize.split(',')
268args.constProbSize = int(args.constProbSize.split(',')[0])
269args.device = args.device.split(',')
270args.lengthx = args.lengthx.split(',')
271args.lengthy = args.lengthy.split(',')
272args.lengthz = args.lengthz.split(',')
273args.prime_factor = args.prime_factor.split(',')
274if args.problemsize:
275    args.problemsize = args.problemsize.split(',')
276args.inputlayout = args.inputlayout.split(',')
277args.outputlayout = args.outputlayout.split(',')
278args.placeness = args.placeness.split(',')
279args.precision = args.precision.split(',')
280
281
282
283printLog('Executing for label: '+str(args.label))
284#check parameters for sanity
285
286# batchSize of 'max' must not be in a list (does not get on well with others)
287#if args.batchSize.count('max') and len(args.batchSize) > 1:
288if ( args.batchSize.count('max') or args.batchSize.count('adapt') )and len(args.batchSize) > 1:
289    printLog('ERROR: --batchsize max must not be in a comma delimited list')
290    quit()
291
292
293# in case of an in-place transform, input and output layouts must be the same (otherwise: *boom*)
294#for n in args.placeness:
295#    if n == 'in' or n == 'inplace':
296#        if len(args.inputlayout) > 1 or len(args.outputlayout) > 1 or args.inputlayout[0] != args.outputlayout[0]:
297#            printLog('ERROR: if transformation is in-place, input and output layouts must match')
298#            quit()
299
300# check for valid values in precision
301for n in args.precision:
302    if n != 'single' and n != 'double':
303        printLog('ERROR: invalid value for precision')
304        quit()
305
306def isPrime(n):
307    import math
308    n = abs(n)
309    i = 2
310    while i <= math.sqrt(n):
311        if n%i == 0:
312            return False
313        i += 1
314    return True
315
316def findFactors(number):
317    iter_space = range(1, number+1)
318    prime_factor_list = []
319    for curr_iter in iter_space:
320        if isPrime(curr_iter) == True:
321            #print 'curr_iter_prime: ', curr_iter
322            if number%curr_iter == 0:
323                prime_factor_list.append(curr_iter)
324    return prime_factor_list
325
326
327#Type : Function
328#Input: num, a number which we need to factorize
329#Return Type: list
330#Details: This function returns only the prime factors on an input number
331#         e.g: input: 20, returns: [2,2,5]
332#              input: 32, returns: [2,2,2,2,2]
333def factor(num):
334    if num == 1:
335        return [1]
336    i = 2
337    limit = num**0.5
338    while i <= limit:
339        if num % i == 0:
340            ret = factor(num/i)
341            ret.append(i)
342            return ret
343        i += 1
344    return [num]
345
346def validateFactors(flist):
347    ref_list = [1,2,3,5]
348    if flist==ref_list:
349        return True
350    if len(flist) > len(ref_list):
351        return False
352    for felement in flist:
353        if ref_list.count(felement) != 1:
354            return False
355    return True
356
357#Type : Function
358#Input: num, a number which we need to validate for 1,2,3 or 5 factors
359#Return Type: boolean
360#Details: This function validates an input number for its prime factors
361#         If factors has number other than 1,2,3 or 5 then return false else return true
362#         e.g: input: 20, returns: True
363#              input: 28, returns: False
364def validate_number_for_1235(num):
365    if num == 0:
366        return True
367    set1235 = set([1,2,3,5])
368    setPrimeFactors = set(factor(num))
369    setPrimeFactors = setPrimeFactors | set1235 #performed union of two sets
370    #if still the sets are same then we are done!!!
371    #else we got few factors other than 1,2,3 or 5 and we should invalidate
372    #the input number
373    if setPrimeFactors ==  set1235:
374        return True
375    return False
376
377
378def getValidNumbersInRange(rlist):
379    valid_number_list = []
380    for relement in rlist:
381        prime_factors = findFactors(relement)
382        if validateFactors(prime_factors) == True:
383            valid_number_list.append(relement)
384    return valid_number_list
385
386def get_next_num_with_1235_factors(start):
387    start+=1
388    while not validateFactors(findFactors(start)):
389        start+=1
390    return start
391
392
393def check_number_for_1235_factors(number):
394    #printLog('number:'+ number)
395    factors = findFactors(number)
396    #printLog('factors:'+ factors)
397    if not validateFactors(factors):
398        printLog("ERROR: --{0} must have only 1,2,3,5 as factors")
399        return False
400    return True
401
402
403
404def check_for_1235_factors(values, option):
405    #print 'values: ', values
406    for n in values:
407        for m in n.replace('-',',').split(','):
408            if not validate_number_for_1235(int(m)):
409                print 'ERROR: --{0} must specify number with only 1,2,3,5 as factors'.format(option)
410                quit()
411            #print 'Valid number for :',option,':', m
412
413
414if args.library == 'clFFT':
415    check_for_1235_factors(args.lengthx, 'lengthx')
416    check_for_1235_factors(args.lengthy, 'lengthy')
417    check_for_1235_factors(args.lengthz, 'lengthz')
418
419
420
421if not os.path.isfile(args.prefix+executable(args.library)):
422    printLog("ERROR: Could not find client named {0}".format(executable(args.library)))
423    quit()
424
425
426def get235RadicesNumberInRange(minimum, maximum):
427    if minimum == 0 and maximum == 0:
428        return [0]
429    numbers = generate235Radices(maximum)
430    minIndex = numbers.index(minimum)
431    maxIndex = numbers.index(maximum)
432    return numbers[minIndex:maxIndex+1]
433
434#expand ranges
435class Range:
436    def __init__(self, ranges, defaultStep='+1'):
437        self.expanded = []
438        for thisRange in ranges:
439            if thisRange != 'max' and thisRange != 'adapt' :
440                if thisRange.count(':'):
441                    self._stepAmount = thisRange.split(':')[1]
442                else:
443                    self._stepAmount = defaultStep
444                thisRange = thisRange.split(':')[0]
445
446                if self._stepAmount.count('x'):
447                    self._stepper = '_mult'
448                    self._stepAmount = self._stepAmount.lstrip('+x')
449                    self._stepAmount = int(self._stepAmount)
450                elif self._stepAmount.count('l'):
451                    self._stepper = '_next_num_with_1235_factor'
452                    self._stepAmount = 0
453                else:
454                    self._stepper = '_add'
455                    self._stepAmount = self._stepAmount.lstrip('+x')
456                    self._stepAmount = int(self._stepAmount)
457
458                if thisRange.count('-'):
459                    self.begin = int(thisRange.split('-')[0])
460                    self.end = int(thisRange.split('-')[1])
461                else:
462                    self.begin = int(thisRange.split('-')[0])
463                    self.end = int(thisRange.split('-')[0])
464                self.current = self.begin
465
466           # _thisRangeExpanded = []
467            if thisRange == 'max':
468                self.expanded = self.expanded + ['max']
469            elif thisRange == 'adapt':
470                self.expanded = self.expanded + ['adapt']
471            elif self.begin == 0 and self._stepper == '_mult':
472                self.expanded = self.expanded + [0]
473            else:
474                if self._stepper == '_next_num_with_1235_factor':
475                    self.expanded = self.expanded + get235RadicesNumberInRange(self.current, self.end)
476                else:
477                    while self.current <= self.end:
478                        self.expanded = self.expanded + [self.current]
479                        self._step()
480
481            # now we want to uniquify and sort the expanded range
482            self.expanded = list(set(self.expanded))
483            self.expanded.sort()
484
485    # advance current value to next
486    def _step(self):
487        getattr(self, self._stepper)()
488
489    def _mult(self):
490        self.current = self.current * self._stepAmount
491
492    def _add(self):
493        self.current = self.current + self._stepAmount
494
495    def _next_num_with_1235_factor(self):
496        self.current = get_next_num_with_1235_factors(self.current)
497
498
499args.batchSize = Range(args.batchSize).expanded
500args.lengthx = Range(args.lengthx, 'l').expanded
501args.lengthy = Range(args.lengthy, 'l').expanded
502args.lengthz = Range(args.lengthz, 'l').expanded
503
504
505def create_prime_factors(args,input_list):
506  powers2=[1]
507  powers3=[1]
508  powers5=[1]
509  powers7=[1]
510  if '2' in args.prime_factor:
511    powers2+=[2**x for x in range(1,int(math.floor(math.log(max(input_list),2)+1)))]
512  if '3' in args.prime_factor:
513    powers3+=[3**x for x in range(1,int(math.floor(math.log(max(input_list),3)+1)))]
514  if '5' in args.prime_factor:
515    powers5+=[5**x for x in range(1,int(math.floor(math.log(max(input_list),5)+1)))]
516  if '7' in args.prime_factor:
517    powers7+=[7**x for x in range(1,int(math.floor(math.log(max(input_list),7)+1)))]
518
519
520  xlist=[]
521  for i in powers2:
522    for j in powers3:
523      for k in powers5:
524        for l in powers7:
525          dummy=int(i)*int(j)*int(k)*int(l)
526          if(dummy<=max(input_list)) and (dummy>=min(input_list)):
527            xlist.append(dummy)
528
529  xlist=sorted(xlist)
530  xlist=xlist[:int(args.test_count)] #snafu
531  return xlist
532
533args.lengthx=create_prime_factors(args,args.lengthx)
534args.lengthy=create_prime_factors(args,args.lengthy)
535args.lengthz=create_prime_factors(args,args.lengthz)
536
537#expand problemsizes ('XxYxZ:batch')
538#print "args.problemsize--1-->", args.problemsize
539if args.problemsize and args.problemsize[0] != 'None':
540    i = 0
541    while i < len(args.problemsize):
542        args.problemsize[i] = args.problemsize[i].split(':')
543        args.problemsize[i][0] = args.problemsize[i][0].split('x')
544        i = i+1
545
546
547#create the problem size combinations for each run of the client
548# A: This part creats a product of all possible combinations. Too many cases in 2/3D
549#problem_size_combinations = itertools.product(args.lengthx, args.lengthy, args.lengthz, args.batchSize)
550#problem_size_combinations = list(itertools.islice(problem_size_combinations, None))
551
552if args.lengthy[0]==1:
553  args.lengthy=[1]*len(args.lengthx)
554if args.lengthz[0]==1:
555  args.lengthz=[1]*len(args.lengthx)
556
557dummy=[args.batchSize[0]]*len(args.lengthx)
558problem_size_combinations=zip(args.lengthx,args.lengthy,args.lengthz,dummy)
559
560#print "args.problemsize--2-->", args.problemsize
561#add manually entered problem sizes to the list of FFTs to crank out
562manual_test_combinations = []
563if args.problemsize and args.problemsize[0] != 'None':
564    for n in args.problemsize:
565        x = []
566        y = []
567        z = []
568        batch = []
569
570        x.append(int(n[0][0]))
571
572        if len(n[0]) >= 2:
573            y.append(int(n[0][1]))
574        else:
575            y.append(1)
576
577        if len(n[0]) >= 3:
578            z.append(int(n[0][2]))
579        else:
580            z.append(1)
581
582        if len(n) > 1:
583            batch.append(int(n[1]))
584        else:
585            batch.append(1)
586
587        combos = itertools.product(x, y, z, batch)
588        combos = list(itertools.islice(combos, None))
589        for n in combos:
590            manual_test_combinations.append(n)
591        # manually entered problem sizes should not be plotted (for now). they may still be output in a table if requested
592
593
594problem_size_combinations = problem_size_combinations + manual_test_combinations
595
596#create final list of all transformations (with problem sizes and transform properties)
597test_combinations = itertools.product(problem_size_combinations, args.device, args.inputlayout, args.outputlayout, args.placeness, args.precision)
598test_combinations = list(itertools.islice(test_combinations, None))
599test_combinations = [TestCombination(params[0][0], params[0][1], params[0][2], params[0][3], params[1], params[2], params[3], params[4], params[5], args.label) for params in test_combinations]
600
601if args.iniFilename != None:
602  array=np.genfromtxt(args.iniFilename, names=True, delimiter=',', dtype=None)
603  test_combinations = [TestCombination(params[0],params[1], params[2], params[3], params[4],params[5],params[6],params[7],params[8],args.label) for params in array]
604
605#print("lenghtx= ",test_combinations[0].x)
606#print("lenghty= ",test_combinations[0].y)
607#print("lenghtz= ",test_combinations[0].z)
608#print("placeness= ",test_combinations[0].placeness)
609
610
611
612#turn each test combination into a command, run the command, and then stash the gflops
613result = [] # this is where we'll store the results for the table
614
615
616#open output file and write the header
617
618if args.tableOutputFilename == None:
619  if args.library == 'cuFFT':
620    args.tableOutputFilename = 'cuFFT_' + 'x_'+ str(args.lengthx[0]) + '_y_'+str(args.lengthy[0])+'_z_'+str(args.lengthz[0])+'_'+str(args.precision[0]) +'_'+datetime.now().isoformat().replace(':','.') + '.txt'
621  elif args.library=='clFFT':
622    args.tableOutputFilename = 'clFFT_' + 'x_'+ str(args.lengthx[0]) + '_y_'+str(args.lengthy[0])+'_z_'+str(args.lengthz[0])+'_'+str(args.precision[0])+ '_'+datetime.now().isoformat().replace(':','.') + '.txt'
623else:
624   if os.path.isfile(args.tableOutputFilename):
625       oldname = args.tableOutputFilename
626       args.tableOutputFilename = args.tableOutputFilename + datetime.now().isoformat().replace(':','.')
627       message = 'A file with the name ' + oldname + ' already exists. Changing filename to ' + args.tableOutputFilename
628       printLog(message)
629
630
631printLog('table header---->'+ str(tableHeader))
632
633table = open(args.tableOutputFilename, 'w')
634table.write(tableHeader + '\n')
635table.flush()
636if args.constProbSize == -1:
637   args.constProbSize = maxBatchSize(1, 1, 1, args.inputlayout[0], args.precision[0], executable(args.library), '-' + args.device[0])
638args.constProbSize = int(args.constProbSize)
639
640
641printLog('Total combinations =  '+str(len(test_combinations)))
642
643vi = 0
644for params in test_combinations:
645    if vi>=int(args.test_count):
646      break
647    vi = vi+1
648    printLog("")
649    printLog('preparing command: '+ str(vi))
650    device = params.device
651    lengthx = str(params.x)
652    lengthy = str(params.y)
653    lengthz = str(params.z)
654    inlayout=str(params.inlayout)
655    outlayout=str(params.outlayout)
656    prefix=str(args.prefix)
657
658
659    if params.batchsize == 'max':
660        batchSize = maxBatchSize(lengthx, lengthy, lengthz, params.inlayout, params.precision, executable(args.library), '-' + device)
661    elif params.batchsize == 'adapt':
662        batchSize = str(args.constProbSize/(int(lengthx)*int(lengthy)*int(lengthz)))
663    else:
664        batchSize = str(params.batchsize)
665
666    if params.placeness == 'inplace' or params.placeness == 'in':
667        placeness = ''
668    elif params.placeness == 'outofplace' or params.placeness == 'out':
669        placeness = '--outPlace'
670    else:
671        printLog('ERROR: invalid value for placeness when assembling client command')
672
673    if params.precision == 'single':
674        precision = ''
675    elif params.precision == 'double':
676        precision = '--double'
677    else:
678        printLog('ERROR: invalid value for precision when assembling client command')
679
680
681    #set up arguments here
682    if args.library == 'clFFT':
683        arguments = [prefix+ executable(args.library),
684                     '-' + device,
685                     '-x', lengthx,
686                     '-y', lengthy,
687                     '-z', lengthz,
688                     '--batchSize', batchSize,
689                     '--inLayout', inlayout,
690                     '--outLayout',outlayout,
691                     placeness,
692                     precision,
693                     '-p', args.reps]
694    elif args.library == 'cuFFT':
695        if  inlayout[0]=='1'  and outlayout[0]=='1':
696          cuFFT_type='1'
697        elif inlayout[0]=='3' and outlayout[0]=='5':
698          cuFFT_type='3'
699        elif inlayout[0]=='5' and outlayout[0]=='3':
700          cuFFT_type='2'
701        else:
702          print"Wrong input/outputlayout. Only C2C/R2C/C2R are supported for Cuda"
703          exit()
704        arguments=[prefix+executable(args.library),
705                     '-x', lengthx,
706                     '-y', lengthy,
707                     '-z', lengthz,
708                     '-b', batchSize,
709                     '-p',args.reps,
710                     '-d',str(int(args.precision[0]=='double')),
711                     '-type',cuFFT_type]
712
713    writeline = True
714    try:
715        arguments=' '.join(arguments)
716        printLog('Executing Command: '+str(arguments))
717        output = checkTimeOutPut(arguments)
718        output = output.split(os.linesep);
719        printLog('Execution Successfull---------------\n')
720
721    except errorHandler.ApplicationException as ae:
722        writeline = False
723        printLog('ERROR: Command is taking too much of time '+ae.message+'\n'+'Command: \n'+str(arguments))
724        continue
725    except subprocess.CalledProcessError as clientCrash:
726        print 'Command execution failure--->'
727        if clientCrash.output.count('CLFFT_INVALID_BUFFER_SIZE'):
728            writeline = False
729            printLog('Omitting line from table - problem is too large')
730        else:
731            writeline = False
732            printLog('ERROR: client crash. Please report the following error message (with \'CLFFT_*\' error code, if given, and the parameters used to invoke measurePerformance.py) \n'+clientCrash.output+'\n')
733            printLog('IN ORIGINAL WE CALL QUIT HERE - 1\n')
734            continue
735
736    for x in output:
737        if x.count('out of memory'):
738            writeline = False
739            printLog('ERROR: Omitting line from table - problem is too large')
740
741    if writeline:
742        try:
743            if args.library == 'cuFFT':
744              output = itertools.ifilter( lambda x: x.count('gflops'), output)
745            else:
746              output = itertools.ifilter( lambda x: x.count('gflops'), output)
747
748            output = list(itertools.islice(output, None))
749            thisResult = re.search('\d+\.*\d*e*-*\d*$', output[-1])
750            if args.library == 'cuFFT':
751                thisResult = re.search('[-+]?\d*\.\d+|\d+$', output[-1])
752            thisResult = float(thisResult.group(0))
753
754            thisResult = (params.x, params.y, params.z, batchSize, params.device, params.inlayout, params.outlayout, params.placeness, params.precision, params.label, thisResult)
755
756            outputRow = ''
757            for x in thisResult:
758                outputRow = outputRow + str(x) + ','
759            outputRow = outputRow.rstrip(',')
760            table.write(outputRow + '\n')
761            table.flush()
762        except:
763			printLog('ERROR: Exception occurs in GFLOP parsing')
764    else:
765        if(len(output) > 0):
766            if output[0].find('nan') or output[0].find('inf'):
767                printLog( 'WARNING: output from client was funky for this run. skipping table row')
768            else:
769                prinLog('ERROR: output from client makes no sense')
770                printLog(str(output[0]))
771                printLog('IN ORIGINAL WE CALL QUIT HERE - 2\n')
772        else:
773            prinLog('ERROR: output from client makes no sense')
774            #quit()
775printLog("=========================MEASURE PERFORMANCE ENDS===========================\n")
776#
777#"""
778#print a pretty table
779#"""
780#if args.tableOutputFilename == None:
781#   args.tableOutputFilename = 'results' + datetime.now().isoformat().replace(':','.') + '.txt'
782#else:
783#   if os.path.isfile(args.tableOutputFilename):
784#       oldname = args.tableOutputFilename
785#       args.tableOutputFilename = args.tableOutputFilename + datetime.now().isoformat().replace(':','.')
786#       message = 'A file with the name ' + oldname + ' already exists. Changing filename to ' + args.tableOutputFilename
787#       print message
788#
789#table = open(args.tableOutputFilename, 'w')
790#table.write(tableHeader + '\n')
791#for x in result:
792#   row = ''
793#   for y in x:
794#       row = row + str(y) + ','
795#   row = row[:-1] #chomp off the trailing comma
796#   table.write(row + '\n')
797