|
52 | 52 |
|
53 | 53 |
|
54 | 54 | import sys
|
55 |
| -import os |
| 55 | +import os, glob |
56 | 56 |
|
57 | 57 | # In case we are run from the source directory, we don't want to import the
|
58 | 58 | # project from there:
|
@@ -310,8 +310,16 @@ def main(argv):
|
310 | 310 | out = subprocess.check_output(['git', 'rev-parse', commit_a])
|
311 | 311 | commit_a = out.strip().decode('ascii')
|
312 | 312 |
|
| 313 | + # generate config file with the required build options |
| 314 | + asv_cfpath = [ |
| 315 | + '--config', asv_compare_config( |
| 316 | + os.path.join(ROOT_DIR, 'benchmarks'), args, |
| 317 | + # to clear the cache if the user changed build options |
| 318 | + (commit_a, commit_b) |
| 319 | + ) |
| 320 | + ] |
313 | 321 | cmd = ['asv', 'continuous', '-e', '-f', '1.05',
|
314 |
| - commit_a, commit_b] + bench_args |
| 322 | + commit_a, commit_b] + asv_cfpath + bench_args |
315 | 323 | ret = subprocess.call(cmd, cwd=os.path.join(ROOT_DIR, 'benchmarks'))
|
316 | 324 | sys.exit(ret)
|
317 | 325 |
|
@@ -361,7 +369,6 @@ def main(argv):
|
361 | 369 | else:
|
362 | 370 | sys.exit(1)
|
363 | 371 |
|
364 |
| - |
365 | 372 | def build_project(args):
|
366 | 373 | """
|
367 | 374 | Build a dev version of the project.
|
@@ -491,6 +498,98 @@ def build_project(args):
|
491 | 498 |
|
492 | 499 | return site_dir, site_dir_noarch
|
493 | 500 |
|
| 501 | +def asv_compare_config(bench_path, args, h_commits): |
| 502 | + """ |
| 503 | + Fill the required build options through custom variable |
| 504 | + 'numpy_build_options' and return the generated config path. |
| 505 | + """ |
| 506 | + conf_path = os.path.join(bench_path, "asv_compare.conf.json.tpl") |
| 507 | + nconf_path = os.path.join(bench_path, "_asv_compare.conf.json") |
| 508 | + |
| 509 | + # add custom build |
| 510 | + build = [] |
| 511 | + if args.parallel > 1: |
| 512 | + build += ["-j", str(args.parallel)] |
| 513 | + if args.cpu_baseline: |
| 514 | + build += ["--cpu-baseline", args.cpu_baseline] |
| 515 | + if args.cpu_dispatch: |
| 516 | + build += ["--cpu-dispatch", args.cpu_dispatch] |
| 517 | + if args.disable_optimization: |
| 518 | + build += ["--disable-optimization"] |
| 519 | + |
| 520 | + is_cached = asv_substitute_config(conf_path, nconf_path, |
| 521 | + numpy_build_options = ' '.join([f'\\"{v}\\"' for v in build]), |
| 522 | + ) |
| 523 | + if not is_cached: |
| 524 | + asv_clear_cache(bench_path, h_commits) |
| 525 | + return nconf_path |
| 526 | + |
| 527 | +def asv_clear_cache(bench_path, h_commits, env_dir="env"): |
| 528 | + """ |
| 529 | + Force ASV to clear the cache according to specified commit hashes. |
| 530 | + """ |
| 531 | + # FIXME: only clear the cache from the current environment dir |
| 532 | + asv_build_pattern = os.path.join(bench_path, env_dir, "*", "asv-build-cache") |
| 533 | + for asv_build_cache in glob.glob(asv_build_pattern, recursive=True): |
| 534 | + for c in h_commits: |
| 535 | + try: shutil.rmtree(os.path.join(asv_build_cache, c)) |
| 536 | + except OSError: pass |
| 537 | + |
| 538 | +def asv_substitute_config(in_config, out_config, **custom_vars): |
| 539 | + """ |
| 540 | + A workaround to allow substituting custom tokens within |
| 541 | + ASV configuration file since there's no official way to add custom |
| 542 | + variables(e.g. env vars). |
| 543 | +
|
| 544 | + Parameters |
| 545 | + ---------- |
| 546 | + in_config : str |
| 547 | + The path of ASV configuration file, e.g. '/path/to/asv.conf.json' |
| 548 | + out_config : str |
| 549 | + The path of generated configuration file, |
| 550 | + e.g. '/path/to/asv_substituted.conf.json'. |
| 551 | +
|
| 552 | + The other keyword arguments represent the custom variables. |
| 553 | +
|
| 554 | + Returns |
| 555 | + ------- |
| 556 | + True(is cached) if 'out_config' is already generated with |
| 557 | + the same '**custom_vars' and updated with latest 'in_config', |
| 558 | + False otherwise. |
| 559 | +
|
| 560 | + Examples |
| 561 | + -------- |
| 562 | + See asv_compare_config(). |
| 563 | + """ |
| 564 | + assert in_config != out_config |
| 565 | + assert len(custom_vars) > 0 |
| 566 | + |
| 567 | + def sdbm_hash(*factors): |
| 568 | + chash = 0 |
| 569 | + for f in factors: |
| 570 | + for char in str(f): |
| 571 | + chash = ord(char) + (chash << 6) + (chash << 16) - chash |
| 572 | + chash &= 0xFFFFFFFF |
| 573 | + return chash |
| 574 | + |
| 575 | + vars_hash = sdbm_hash(custom_vars, os.path.getmtime(in_config)) |
| 576 | + try: |
| 577 | + with open(out_config, "r") as wfd: |
| 578 | + hash_line = wfd.readline().split('hash:') |
| 579 | + if len(hash_line) > 1 and int(hash_line[1]) == vars_hash: |
| 580 | + return True |
| 581 | + except IOError: |
| 582 | + pass |
| 583 | + |
| 584 | + custom_vars = {f'{{{k}}}':v for k, v in custom_vars.items()} |
| 585 | + with open(in_config, "r") as rfd, open(out_config, "w") as wfd: |
| 586 | + wfd.write(f"// hash:{vars_hash}\n") |
| 587 | + wfd.write("// This file is automatically generated by runtests.py\n") |
| 588 | + for line in rfd: |
| 589 | + for key, val in custom_vars.items(): |
| 590 | + line = line.replace(key, val) |
| 591 | + wfd.write(line) |
| 592 | + return False |
494 | 593 |
|
495 | 594 | #
|
496 | 595 | # GCOV support
|
|
0 commit comments