From ea017431b07a05e1c2b5b15b41f1b3247657215f Mon Sep 17 00:00:00 2001 From: Ben van Werkhoven Date: Thu, 17 Sep 2026 16:27:09 +0200 Subject: [PATCH] support .json.gz in addition to .json --- kernel_tuner/interface.py | 23 +++++++++++++++++++---- kernel_tuner/util.py | 25 +++++++++++++++++-------- test/test_cache_file.json.gz | Bin 0 -> 2190 bytes test/test_runners.py | 9 +++++++++ 4 files changed, 45 insertions(+), 12 deletions(-) create mode 100644 test/test_cache_file.json.gz diff --git a/kernel_tuner/interface.py b/kernel_tuner/interface.py index 54b742a2..c1d72608 100644 --- a/kernel_tuner/interface.py +++ b/kernel_tuner/interface.py @@ -780,7 +780,7 @@ def tune_kernel( def preprocess_cache(filepath): if isinstance(filepath, Path): filepath = str(filepath.resolve()) - if filepath[-5:] != ".json": + if filepath[-5:] != ".json" and filepath[-8:] != ".json.gz": filepath += ".json" return filepath @@ -877,11 +877,26 @@ def preprocess_cache(filepath): def tune_cache( - cache_path, + cachefile, restrictions=None, **kwargs, ): - cache = util.read_cache(cache_path, open_cache=False) + """ Simulate a tuning session based on a Kernel Tuner cache file + + See tune_kernel for full documentation of options. + + :param cachefile: filename or path to the cachefile + :type cachefile: string or Path + + :param restrictions: search space restrictions / constraints, if not + passed these are simply inferred from the cachefile, which may be + much less efficient. Default: None + :type restrictions: list of string expressions or lambdas + + """ + if isinstance(cachefile, Path): + cachefile = str(cachefile.resolve()) + cache = util.read_cache(cachefile, open_cache=False) tune_args = util.infer_args_from_cache(cache) _restrictions = [util.infer_restrictions_from_cache(cache)] @@ -894,7 +909,7 @@ def tune_cache( tune_args.update(kwargs) - return tune_kernel(**tune_args, cache=cache_path, restrictions=_restrictions, simulation_mode=True) + return tune_kernel(**tune_args, cache=cachefile, restrictions=_restrictions, simulation_mode=True) _run_kernel_docstring = ( diff --git a/kernel_tuner/util.py b/kernel_tuner/util.py index 5ceb3cce..a917b68f 100644 --- a/kernel_tuner/util.py +++ b/kernel_tuner/util.py @@ -2,6 +2,7 @@ import ast import errno +import gzip import json import logging import os @@ -1380,6 +1381,13 @@ def check_matching_problem_size(cached_problem_size, problem_size): ) +def open_cachefile(cachefile, mode): + """ Open a cachefile for reading or writing (depending on mode) """ + if cachefile[-3:] == ".gz": + return gzip.open(cachefile, mode) + return open(cachefile, mode) + + def process_cache(cachefile, kernel_options, tuning_options, runner): """Cache file for storing tuned configurations. @@ -1391,7 +1399,8 @@ def process_cache(cachefile, kernel_options, tuning_options, runner): kernel_name: "name of kernel" problem_size: (int, int, int) tune_params_keys: list - tune_params: + tune_params: dict + objective: string cache: { "x1,x2,..xN": {"block_size_x": x1, ..., time=0.234342}, "y1,y2,..yN": {"block_size_x": y1, ..., time=0.134233}, @@ -1427,7 +1436,7 @@ def process_cache(cachefile, kernel_options, tuning_options, runner): contents = json.dumps(c, cls=NpEncoder, indent="")[:-3] # except the last "}\n}" # write the header to the cachefile - with open(cachefile, "w") as f: + with open_cachefile(cachefile, "wt") as f: f.write(contents) return {} @@ -1471,7 +1480,7 @@ def process_cache(cachefile, kernel_options, tuning_options, runner): def correct_open_cache(cachefile, open_cache=True): """If cache file was not properly closed, pretend it was properly closed.""" - with open(cachefile, "r") as f: + with open_cachefile(cachefile, "rt") as f: filestr = f.read().strip() # if file was not properly closed, pretend it was properly closed @@ -1484,7 +1493,7 @@ def correct_open_cache(cachefile, open_cache=True): else: if open_cache: # if it was properly closed, open it for appending new entries - with open(cachefile, "w") as f: + with open_cachefile(cachefile, "wt") as f: f.write(filestr[:-3] + ",") return filestr @@ -1519,12 +1528,12 @@ def close_cache(cachefile): if not os.path.isfile(cachefile): raise ValueError("close_cache expects cache file to exist") - with open(cachefile, "r") as fh: + with open_cachefile(cachefile, "rt") as fh: contents = fh.read() # close to file to make sure it can be read by JSON parsers if contents[-1] == ",": - with open(cachefile, "w") as fh: + with open_cachefile(cachefile, "wt") as fh: fh.write(contents[:-1] + "}\n}") @@ -1542,14 +1551,14 @@ def store_cache(key, params, cachefile, cache): output_params[k] = str(v) if cachefile: - with open(cachefile, "a") as f: + with open_cachefile(cachefile, "at") as f: f.write("\n" + json.dumps({key: output_params}, cls=NpEncoder)[1:-1] + ",") def dump_cache(obj: str, tuning_options): """Dumps a string in the cache, this omits the several checks of store_cache() to speed up the process - with great power comes great responsibility!""" if isinstance(tuning_options.cache, dict) and tuning_options.cachefile: - with open(tuning_options.cachefile, "a") as cachefile: + with open(tuning_options.cachefile, "at") as cachefile: cachefile.write(obj) diff --git a/test/test_cache_file.json.gz b/test/test_cache_file.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..80dc1bbf273e817bda80ed2cdecd0e328669565e GIT binary patch literal 2190 zcmV;92yyoxiwFqk7c6Q319W9`bYEj(V`ybxW@&6?E^2dcZUD8KPj4GH5XJBL6oIcz z1rCS98Rk}?mtJ}(ilRUf7>c8|Mq)d#-T%mU?;Ebn zc!{5jcbng@uQr#r>zmER>z5bb{_xG$-+cA*yYGK|`Be%bT)Y~Fz2Ds5ZazE>`+alu zcz1ufe)n!S;N$(>+Yg(Y%ZKZ~eFTNDedF=B+s)<2_5J$h;qv|FuLr#OQ+=nt`}V`# z)%*IP%Revb%WtNi!$d?DTSDxUU*ag`m|lXtM%2doAJV7ZALHD7n{|btl!1sb=~r? z3MnXOFrj2dsg#+450ee?pRl5s&G1nPA%;lJcMM|!Q_zS(AyLMcr8qk(YAjMpiP4HA zCYc{4sm>J>Ma8;x<`N=IRZ`>}IaqJ5nEc|oSX9H%`B5okkC=?BON`AN4SLfo*45q3 z$LkN9%kAo>6jrz!5fdS%_NEYT_t!sPU#%an?{0UWX;`>;yScsk^=5tlem8(tp^%gq z2$v%zX!C)G$NTl;=9j;E6aI|Y+x&6&--KahVrr}rQN9e0+J%hBw{gAdXJ%Y3dHc}B9rlF)okd|QTIApLuoqgtj zw=syY41hs9kZN)mR2A$|8_2s+LgM`8jH$9Icfcwhbs$SiDuBN?syOg~ClfBeHy7m3 z!=eawFVP}KIj?ZN!WL4Bgqh9-sYWg$Tq4ktc54??N~@eD8#E+{V$rPS{tT32757p) zNi@$XB`Xn-vL;pN$`VSMEPzrdQPfP5I$BCqtFg_6LBzb`MhjI-l_Q{$JU>^|5M2N8 zZTM4S2Q3+bhwuxcQ#yemp#rGI3Iwwk7vn)oDHY?Ai>4T)y^NzF&A2g+1g?taHd7x3 zX@K5C?jaDOiD!lCG)Q4=_Ch)_KhGhJ!3rf-2#>^B&Fw>qL;*R@Q=F@rA*NtZEdD^Ntp z%FH>pw&MgLMT7=}xI-JLCF%%9Q!2@^M=C`e&J%DVqn7qF+WPU4kShLD0-}l#oi!v~ zMv;G`XH3H`q&7_qgYa&4X5b7MYS~Kqb`Wf#dLlPic0#)EsO^Dd0NVO@GFBi93a}G#R|LuizQX@Wt zlwr=`mfekrq)A|Y4pJy+)jyYEf~20nC{{`8AY6*}xr$Y7A>62n0Aq)D3NE)0TP(Zw zOt46B6Pye(!dyDITeTo!AxF}MRZ~F}V@=_rlcC}}6QZCVRa_1b9+lAE-7$!Y73>RD z;|$L>XADnd6jHXA(Mj84B&4vR=7hLuYW?CKAq_S8GJasYW!@hi>PWd(+L>ym2%@mfCfL2mp+jhGK7|SdVZ%Cr4m~6I4nQbv zQ)M?Q=Nb~(QSLUpqMLsY2}Q9A{p!(u4FeV4IKh#4YGaeCHh0E zuf$bpu`n5kMp;%d=?YGlg7@VtOKW&fFryi>fDnzM=XsNwVZ&e~=cDUNMT2TUL_mU?iXUl{A zfN9g7Wk^WC{(Wv33{K}D+Lx&)uVAoXtOLFx8cok)6x=0QEiGw?)UV?4PFhuaS z$wT&kKs4_!m?r06&kH6}L462Jv*8kX0iwYVavV`cB9GcR_+j!Mq0{HbNF4)tkQL3_ zBP*w#IuQ|hsL#Lzu1?w`wx?007FBRJ*{h$)1Z) z^8RsAWG-zZ>li>)P$0nMLrP1Md8c<8peU600y;U59iK9J+esi8N#O{WC3=7dLNhcN z%GNpNJWNFotHXyD0%XZD>k8ol*k>|Muzg`Eh*Suid8OQy+F0^{x|pdhZzzc@Jn-a{!5-9G{g+R-eSrrOfP zP8Z_#v~@cuntR&{7V7ZUaO?&(1x$ylVJ0`V5&urXore=zZ`Y!t3(JHQh`Nw#z&s3z zI$H-H7mX#V);*psr4c)nSrJIM($dzK=O7ey#$G}vkFAW(n4k~dzh`*xMThlpMV{y3 zvQbcUHkk)`EQ){06|Tdl*8GedhKahp^l{$p8Ppf@-II-r{M@&<#`6 zvjI7{`vA+B_hpdAl|h*h43PEdqdG^Q)Wf(z)&;Ys$>R~nK 10 +def test_zipped_cache_file(env): + result, _ = tune_kernel(*env, + verbose=True, + cache=cache_filename_zipped, + simulation_mode=True) + assert len(result) > 0 + + def test_constraint_aware_GA(env): options = dict(method="uniform", constraint_aware=True,