GeezerVisonThe World Wide Web, restored to 800 pixels of glory. |
| Home|About|Gaming cabinet|Archives|How it works|Starter sites |
GeezerVison is showing github.com — GitPython/test/performance/bench_repository.py at main · gitpython-developers/GitPython Expand file tree/ Copy pathbench_repository.pyMore file actions 207 lines (163 loc) · 7.19 KB / Copy pathbench_repository.pyFile metadata and controls207 lines (163 loc) · 7.19 KB 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 """Read-only GitPython journeys, measured with pyperf against an existing checkout. Run as a module from the source root so pyperf workers import this checkout: python -m test.performance.bench_repository --repo /path/to/repo --expect-backend gix -o gix.json """ from hashlib import sha256 from importlib.metadata import version import json import os from pathlib import Path import subprocess import pyperf from git import Repo, _backend def inventory(repo): return { "head": repo.head.commit.hexsha if repo.head.is_detached else repo.head.reference.path, "refs": sorted(ref.path for ref in repo.references), } def history(repo): return [ [commit.hexsha, str(commit.author), commit.authored_date, commit.message] for commit in repo.iter_commits("HEAD", max_count=25, first_parent=True) ] def browse(repo): tree = repo.commit("HEAD").tree blob = tree / "README.md" content = blob.data_stream.read() return { "entries": [[entry.path, entry.mode, entry.hexsha] for entry in tree], "readme": sha256(content).hexdigest(), } def index(repo): return sorted([entry.path, entry.stage, entry.mode, entry.hexsha] for entry in repo.index.iter_entries()) def submodules(repo): return [[module.name, module.path, module.hexsha, module.url, module.branch_path] for module in repo.submodules] def revision_paths(repo): objects = [repo.rev_parse(revision) for revision in ("HEAD:README.md", "HEAD:git", ":README.md")] return [[obj.hexsha, obj.path, obj.mode] for obj in objects] def object_readback(repo): commit = repo.commit("HEAD") # Read the same bytes used by serialization, without writing objects or stripping signatures. return [sha256(obj.data_stream.read()).hexdigest() for obj in (commit, commit.tree)] def graph(repo): tip, parent = repo.commit("HEAD"), repo.commit("HEAD~1") return { "count": tip.count(), "merge_base": [commit.hexsha for commit in repo.merge_base(parent, tip)], "is_ancestor": repo.is_ancestor(parent, tip), } def changes(repo): tip = repo.commit("HEAD") return { "diff": [[diff.change_type, diff.a_path, diff.b_path] for diff in tip.parents[0].diff(tip)], "stats": tip.stats.total, } def patch(repo): tip = repo.commit("HEAD") return [sha256(diff.diff).hexdigest() for diff in tip.parents[0].diff(tip, create_patch=True)] def worktree(repo): return { "dirty": repo.is_dirty(untracked_files=True), "untracked": sorted(repo.untracked_files), "ignored": repo.ignored(".benchmark-cache/probe"), } # Add a named public-API operation here: it is measured separately and joins the # complete journey automatically. Return JSON-compatible data for parity checks. MEASUREMENTS = { "inventory": inventory, "history_25": history, "browse_tree_and_blob": browse, "read_index": index, "submodule_inventory": submodules, "revision_paths": revision_paths, "object_readback": object_readback, "revision_graph": graph, "diff_and_stats": changes, "patch_diff": patch, "worktree_status": worktree, } def journey(repo): return {name: operation(repo) for name, operation in MEASUREMENTS.items()} def open_repository(path): with Repo(path) as opened: return [opened.bare, opened.object_format, opened.ref_format] def discover_repository(path): with Repo(path, search_parent_directories=True) as opened: return [opened.bare, opened.object_format, opened.ref_format] def worker_arguments(cmd, args): cmd.extend(["--repo", str(args.repo), "--expect-backend", args.expect_backend]) def source_digest(root): digest = sha256() sources = [root / "VERSION", *(root / "git").rglob("*.py"), *(root / "test" / "performance").glob("*.py")] for path in sorted(sources): digest.update(path.relative_to(root).as_posix().encode() + b"\0" + path.read_bytes() + b"\0") return digest.hexdigest() def main(): runner = pyperf.Runner( processes=6, values=3, program_args=("-m", "test.performance.bench_repository"), add_cmdline_args=worker_arguments, ) runner.argparser.add_argument("--repo", type=Path, required=True, help="Existing worktree; never modified") runner.argparser.add_argument("--expect-backend", choices=("cli", "gix"), required=True) args = runner.parse_args() args.repo = args.repo.resolve() if _backend.name != args.expect_backend: raise RuntimeError(f"Expected {args.expect_backend}, imported {_backend.name}; set GIT_PYTHON_BACKEND") # The manager and every worker use the same isolated Git environment. for key in list(os.environ): if key.startswith("GIT_"): del os.environ[key] os.environ.update( GIT_CONFIG_NOSYSTEM="1", GIT_CONFIG_GLOBAL=os.devnull, GIT_OPTIONAL_LOCKS="0", GIT_PYTHON_BACKEND=args.expect_backend, ) args.inherit_environ = [*(args.inherit_environ or []), "GIT_PYTHON_BACKEND"] def git(*arguments, cwd=args.repo): return subprocess.check_output(["git", *arguments], cwd=cwd, text=True).strip() runner.metadata.update( backend=_backend.name, gixpython=version("GixPython"), git_version=git("version"), gitpython_source=source_digest(Path(__file__).resolve().parents[2]), fixture_revision=git("rev-parse", "HEAD"), fixture_tree=git("rev-parse", "HEAD^{tree}"), fixture_status=git("status", "--porcelain") or "clean", fixture_object_format=git("rev-parse", "--show-object-format"), fixture_ref_format=git("rev-parse", "--show-ref-format"), ) with Repo(args.repo) as repo: measurements = [("journey", journey, repo)] measurements.extend((name, operation, repo) for name, operation in MEASUREMENTS.items()) measurements.extend( [ ("open_repository", open_repository, args.repo), ("discover_repository", discover_repository, args.repo / "git" / "objects"), ] ) for name, operation, target in measurements: operation(target) # Warm persistent CLI processes before counting. # Untimed preflight validates parity and records native/fallback # decisions for ONE invocation, rather than calibrated loop counts. before = _backend.statistics() result = operation(target) decisions = [ {"method": method, "outcome": outcome, "count": count - before.get((method, outcome), 0)} for (method, outcome), count in sorted(_backend.statistics().items()) if count > before.get((method, outcome), 0) ] metadata = { "result_digest": sha256(json.dumps(result, sort_keys=True).encode()).hexdigest(), "backend_decisions": json.dumps(decisions, sort_keys=True), "cli_processes": sum( item["count"] for item in decisions if (item["method"], item["outcome"]) == ("Git.execute", "CLI process") ), } runner.bench_func(name, operation, target, metadata=metadata) if __name__ == "__main__": main() |
| You are visitor 01402520 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |