Skip to content

Commit 35e07bd

Browse files
ahornbyfacebook-github-bot
authored andcommitted
add github actions caching
Summary: X-link: facebook/sapling#1005 Speed up github builds with github actions CI caching based on the cache-key mechanism already present in getdeps. Cached fizz windows build completed in 22% of original time, linux build in 54% of the original time, and mac in 72% of original time. This saves a lot of waiting around for PR builds on OSS changes as windows signal is usually the lagging one. Speed ups will vary across the different Meta OSS projects. Windows benefits most from caching dependencies as we don't use system packages there at all, linux next as its default runner is slower than mac, and then finaly mac (the strongest hardware of the default github runners). Github allows [up to 10GB cache per repo](https://github.blog/changelog/2021-11-23-github-actions-cache-size-is-now-increased-to-10gb-per-repository/), expiring data over capacity. You can see the size of the caches generated in the [caches view of githhub actions UX](https://github.com/ahornby/fizz/actions/caches?query=sort%3Asize-desc), looks like our usage is pretty small so far. More background: Github actions caching decides its own compression format (currently it prefers zstd), but they are free to change that in future, hence no .zstd suffix or similar on the cache keys. Github actions caches from main are used from feature branches but not vice versa, hence a PR can't pollute cache for the trunk build. This allows us to benefit from caching on main and PRs where dependency versions match. The final item being built, and dependencies inside the same repo as the final are not cached. A different mechanism would be necessary for those (e.g. using a tool like ccache/sccache or caching cargo/buck2 output). This means that when building EdenFS, sapling could not be cached (its in the same repo), but folly could be as we have a key for it based on the folly-rev.txt file. When there is a cache hit the build step is skipped using extension of the conditionals introduced in previous diff D67839708 Reviewed By: bigfootjon Differential Revision: D67839730 fbshipit-source-id: c384a216eb27ccd3f816e3c31b167232bda571a6
1 parent 56798ec commit 35e07bd

File tree

2 files changed

+62
-6
lines changed

2 files changed

+62
-6
lines changed

build/fbcode_builder/getdeps.py

+51-5
Original file line numberDiff line numberDiff line change
@@ -245,16 +245,16 @@ def __init__(self, cache, loader, m):
245245
self.loader = loader
246246
self.cache = cache
247247

248-
self.cache_file_name = "-".join(
248+
self.cache_key = "-".join(
249249
(
250250
m.name,
251251
self.ctx.get("os"),
252252
self.ctx.get("distro") or "none",
253253
self.ctx.get("distro_vers") or "none",
254254
self.project_hash,
255-
"buildcache.tgz",
256255
)
257256
)
257+
self.cache_file_name = self.cache_key + "-buildcache.tgz"
258258

259259
def is_cacheable(self):
260260
"""We only cache third party projects"""
@@ -560,6 +560,7 @@ def run_project_cmd(self, args, loader, manifest):
560560
else:
561561
manifests = [manifest]
562562

563+
cache = cache_module.create_cache()
563564
for m in manifests:
564565
fetcher = loader.create_fetcher(m)
565566
if isinstance(fetcher, SystemPackageFetcher):
@@ -569,6 +570,10 @@ def run_project_cmd(self, args, loader, manifest):
569570
continue
570571
src_dir = fetcher.get_src_dir()
571572
print(f"{m.name}_SOURCE={src_dir}")
573+
inst_dir = loader.get_project_install_dir_respecting_install_prefix(m)
574+
print(f"{m.name}_INSTALL={inst_dir}")
575+
cached_project = CachedProject(cache, loader, m)
576+
print(f"{m.name}_CACHE_KEY={cached_project.cache_key}")
572577

573578
def setup_project_cmd_parser(self, parser):
574579
parser.add_argument(
@@ -1235,16 +1240,50 @@ def write_job_for_platform(self, platform, args): # noqa: C901
12351240
src_dir_arg = "--src-dir=. "
12361241
has_same_repo_dep = True
12371242

1238-
out.write(" - name: Build %s\n" % m.name)
1239-
if not src_dir_arg:
1240-
# only run the step if needed
1243+
if args.use_build_cache and not src_dir_arg:
1244+
out.write(f" - name: Restore {m.name} from cache\n")
1245+
out.write(f" id: restore_{m.name}\n")
1246+
# only need to restore if would build it
12411247
out.write(
12421248
f" if: ${{{{ steps.paths.outputs.{m.name}_SOURCE }}}}\n"
12431249
)
1250+
out.write(" uses: actions/cache/restore@v4\n")
1251+
out.write(" with:\n")
1252+
out.write(
1253+
f" path: ${{{{ steps.paths.outputs.{m.name}_INSTALL }}}}\n"
1254+
)
1255+
out.write(
1256+
f" key: ${{{{ steps.paths.outputs.{m.name}_CACHE_KEY }}}}-install\n"
1257+
)
1258+
1259+
out.write(" - name: Build %s\n" % m.name)
1260+
if not src_dir_arg:
1261+
if args.use_build_cache:
1262+
out.write(
1263+
f" if: ${{{{ steps.paths.outputs.{m.name}_SOURCE && ! steps.restore_{m.name}.outputs.cache-hit }}}}\n"
1264+
)
1265+
else:
1266+
out.write(
1267+
f" if: ${{{{ steps.paths.outputs.{m.name}_SOURCE }}}}\n"
1268+
)
12441269
out.write(
12451270
f" run: {getdepscmd}{allow_sys_arg} build {build_type_arg}{src_dir_arg}{free_up_disk}--no-tests {m.name}\n"
12461271
)
12471272

1273+
if args.use_build_cache and not src_dir_arg:
1274+
out.write(f" - name: Save {m.name} to cache\n")
1275+
out.write(" uses: actions/cache/save@v4\n")
1276+
out.write(
1277+
f" if: ${{{{ steps.paths.outputs.{m.name}_SOURCE && ! steps.restore_{m.name}.outputs.cache-hit }}}}\n"
1278+
)
1279+
out.write(" with:\n")
1280+
out.write(
1281+
f" path: ${{{{ steps.paths.outputs.{m.name}_INSTALL }}}}\n"
1282+
)
1283+
out.write(
1284+
f" key: ${{{{ steps.paths.outputs.{m.name}_CACHE_KEY }}}}-install\n"
1285+
)
1286+
12481287
out.write(" - name: Build %s\n" % manifest.name)
12491288

12501289
project_prefix = ""
@@ -1363,6 +1402,13 @@ def setup_project_cmd_parser(self, parser):
13631402
action="store",
13641403
default=None,
13651404
)
1405+
parser.add_argument(
1406+
"--no-build-cache",
1407+
action="store_false",
1408+
default=True,
1409+
dest="use_build_cache",
1410+
help="Do not attempt to use the build cache.",
1411+
)
13661412

13671413

13681414
def get_arg_var_name(args):

build/fbcode_builder/getdeps/cargo.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@ def recreate_dir(self, src, dst) -> None:
8282
shutil.rmtree(dst)
8383
simple_copytree(src, dst)
8484

85+
def recreate_linked_dir(self, src, dst) -> None:
86+
if os.path.isdir(dst):
87+
if os.path.islink(dst):
88+
os.remove(dst)
89+
elif os.path.isdir(dst):
90+
shutil.rmtree(dst)
91+
os.symlink(src, dst)
92+
8593
def cargo_config_file(self):
8694
build_source_dir = self.build_dir
8795
if self.cargo_config_file_subdir:
@@ -191,7 +199,9 @@ def _build(self, reconfigure) -> None:
191199
],
192200
)
193201

194-
self.recreate_dir(build_source_dir, os.path.join(self.inst_dir, "source"))
202+
self.recreate_linked_dir(
203+
build_source_dir, os.path.join(self.inst_dir, "source")
204+
)
195205

196206
def run_tests(self, schedule_type, owner, test_filter, retry, no_testpilot) -> None:
197207
if test_filter:

0 commit comments

Comments
 (0)