# -*- coding: utf-8 -*- # PyVkFFT # (c) 2022- : ESRF-European Synchrotron Radiation Facility # authors: # Vincent Favre-Nicolin, favre@esrf.fr # # # pyvkfft script to run short or long unit tests import argparse import os.path import sys import unittest import time import timeit import socket import psutil import numpy as np from pyvkfft.test import TestFFT, TestFFTSystematic from pyvkfft.version import __version__, vkfft_version, vkfft_git_version def cuda_info_str(): try: # The functions used should not create a context on the GPU from ..cuda import cuda_compile_version, cuda_runtime_version, cuda_driver_version return "CUDA: driver %s, runtime %s, compiled %s" % \ (cuda_driver_version(), cuda_runtime_version(), cuda_compile_version()) except: return "" def suite_default(): suite = unittest.TestSuite() load_tests = unittest.defaultTestLoader.loadTestsFromTestCase suite.addTest(load_tests(TestFFT)) return suite def suite_systematic(): suite = unittest.TestSuite() load_tests = unittest.defaultTestLoader.loadTestsFromTestCase suite.addTest(load_tests(TestFFTSystematic)) return suite def make_html_pre_post(overwrite=False): if ('pyvkfft-test1000.html' not in os.listdir()) or overwrite: # if this was called by a parent pyvkfft-test-suite, print that command com = "" for c in psutil.Process(os.getppid()).cmdline(): if "/" in c and "pyvkfft-test-suite" in c: c = os.path.split(c)[-1] com += "%s " % c if 'pyvkfft-test-suite' in com: com = 'Command:%s\n' % com else: com = '' # Need the html header, styles and the results' table beginning vkfft_ver = f'{vkfft_version()}' if 'unknown' in vkfft_git_version() \ else f'{vkfft_version()}[{vkfft_git_version()}]' tmp = '\n \n
\n' \ '\n' \ '\n' \ '%s
Methodology: the included graphs measure the accuracy of the forward ' \ 'and backward transforms: an array is generated with random uniform values ' \ 'between -0.5 and 0.5, and the results of its transform are compared ' \ 'with either pyfftw (in long double precision) if available, or scipy if ' \ 'available, or numpy fft. The L2 curve measures the average square norm ' \ 'difference, and the L∞ the maximum difference.' \ '
Note: for the R2C inverse transform, the result of the forward ' \ 'transform is used instead of re-using the random array (in order to have ' \ 'a proper half-Hermitian array), contrary to what is done for other ' \ 'transforms. This explains why the IFFT R2C maximum (L∞) ' \ 'errors are larger.' \ '
Note 2: some "errors" for DCT may be due to unsupported sizes in VkFFT, ' \ 'which vary depending on the card and language used (amount of ' \ 'shared/local memory). So they just indicate a current limit for the ' \ 'transform sizes rather than a real error.' \ '
[Click on the highlighted cells for details and accuracy graphs ' \
'vs the transform size]
\n' \
'
| GPU | ' \ 'backend | ' \ 'transform | ' \ 'ndim | ' \ 'range | ' \ 'radix | ' \ 'dtype | ' \ 'inplace | ' \ 'LUT | ' \ 'norm | ' \ 'time-duration | ' \ 'FAIL | ' \ 'ERROR | ' \ '|||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| %s | ' % (args.gpu if args.gpu is not None else '-') if args.backend is not None: for a in args.backend: html += a + ' ' else: html += 'all' html += ' | ' if args.systematic: has_graph = False if args.graph is not None: if os.path.exists(args.graph): has_graph = True if has_graph: tmp = '' else: tmp = ' | %s | ' if args.r2c: html += tmp % 'R2C' elif t.dct or t.dst: html += tmp % ('DCT%d' % t.dct) if t.dct else tmp % ('DST%d' % t.dst) else: html += tmp % 'C2C' if t.ndim == 12: html += "1,2 | " elif t.ndim == 123: html += "1,2,3 | " else: html += "%d | " % t.ndim html += "%d-%d" % (args.range[0], args.range[1]) if (t.range_nd_narrow[0] > 0 or t.range_nd_narrow[1] > 0) and t.ndim > 1: html += " [|Ni-N1|<={%d; %d%%N1}]" % \ (t.range_nd_narrow[1], int(t.range_nd_narrow[0] * 100)) elif t.ndim > 1: html += ' (' + 'N,' * (t.ndim - 1) + 'N)' html += " | " if args.bluestein: html += "Bluestein | " elif args.radix is None: html += "- | " else: html += "" for i in (args.radix if len(args.radix) else [2, 3, 5, 7, 11, 13]): html += "%d," % i html = html[:-1] if t.max_pow is not None: html += '[^N,N<=%d]' % t.max_pow html += ' | ' html += "%s | " % ('float64' if args.double else 'float32') html += "%s | " % ('inplace' if args.inplace else 'out-of-place') html += "%s | " % ('True' if args.lut else 'Auto') html += "%d | " % args.norm[0] nbts = '[%5d tests]' % t.nb_test else: html += '' html += 'Regular multi-dimensional C2C/R2C/R2R test | ' nbts = '' html += '%s +%s %s | ' % (time.strftime("%Y-%m-%d %Hh%M:%S", localt0), time.strftime("%Hh %Mm %Ss", time.gmtime(timeit.default_timer() - t0)), nbts) if len(res.failures): html += '' % len(res.failures) else: html += ' | 0 | ' if len(res.errors): html += '' % len(res.errors) else: html += ' | 0 | ' html += '|||||||