##// END OF EJS Templates
deltas: add a debug-delta-find command to analyse delta search...
marmoute -
r50123:b909dd35 default
parent child Browse files
Show More
@@ -73,6 +73,7 b' from . import ('
73 73 repoview,
74 74 requirements,
75 75 revlog,
76 revlogutils,
76 77 revset,
77 78 revsetlang,
78 79 scmutil,
@@ -989,6 +990,65 b' def debugdeltachain(ui, repo, file_=None'
989 990
990 991
991 992 @command(
993 b'debug-delta-find',
994 cmdutil.debugrevlogopts + cmdutil.formatteropts,
995 _(b'-c|-m|FILE REV'),
996 optionalrepo=True,
997 )
998 def debugdeltafind(ui, repo, arg_1, arg_2=None, **opts):
999 """display the computation to get to a valid delta for storing REV
1000
1001 This command will replay the process used to find the "best" delta to store
1002 a revision and display information about all the steps used to get to that
1003 result.
1004
1005 The revision use the revision number of the target storage (not changelog
1006 revision number).
1007
1008 note: the process is initiated from a full text of the revision to store.
1009 """
1010 opts = pycompat.byteskwargs(opts)
1011 if arg_2 is None:
1012 file_ = None
1013 rev = arg_1
1014 else:
1015 file_ = arg_1
1016 rev = arg_2
1017
1018 rev = int(rev)
1019
1020 revlog = cmdutil.openrevlog(repo, b'debugdeltachain', file_, opts)
1021
1022 deltacomputer = deltautil.deltacomputer(
1023 revlog,
1024 write_debug=ui.write,
1025 debug_search=True,
1026 )
1027
1028 node = revlog.node(rev)
1029 p1r, p2r = revlog.parentrevs(rev)
1030 p1 = revlog.node(p1r)
1031 p2 = revlog.node(p2r)
1032 btext = [revlog.revision(rev)]
1033 textlen = len(btext[0])
1034 cachedelta = None
1035 flags = revlog.flags(rev)
1036
1037 revinfo = revlogutils.revisioninfo(
1038 node,
1039 p1,
1040 p2,
1041 btext,
1042 textlen,
1043 cachedelta,
1044 flags,
1045 )
1046
1047 fh = revlog._datafp()
1048 deltacomputer.finddeltainfo(revinfo, fh, target_rev=rev)
1049
1050
1051 @command(
992 1052 b'debugdirstate|debugstate',
993 1053 [
994 1054 (
@@ -931,9 +931,10 b' def _rawgroups(revlog, p1, p2, cachedelt'
931 931
932 932
933 933 class deltacomputer:
934 def __init__(self, revlog, write_debug=None):
934 def __init__(self, revlog, write_debug=None, debug_search=False):
935 935 self.revlog = revlog
936 936 self._write_debug = write_debug
937 self._debug_search = debug_search
937 938
938 939 def buildtext(self, revinfo, fh):
939 940 """Builds a fulltext version of a revision
@@ -980,6 +981,7 b' class deltacomputer:'
980 981 def _builddeltainfo(self, revinfo, base, fh):
981 982 # can we use the cached delta?
982 983 revlog = self.revlog
984 debug_search = self._write_debug is not None and self._debug_search
983 985 chainbase = revlog.chainbase(base)
984 986 if revlog._generaldelta:
985 987 deltabase = base
@@ -1009,13 +1011,27 b' class deltacomputer:'
1009 1011 delta = revinfo.cachedelta[1]
1010 1012 if delta is None:
1011 1013 delta = self._builddeltadiff(base, revinfo, fh)
1014 if debug_search:
1015 msg = b"DBG-DELTAS-SEARCH: uncompressed-delta-size=%d\n"
1016 msg %= len(delta)
1017 self._write_debug(msg)
1012 1018 # snapshotdept need to be neither None nor 0 level snapshot
1013 1019 if revlog.upperboundcomp is not None and snapshotdepth:
1014 1020 lowestrealisticdeltalen = len(delta) // revlog.upperboundcomp
1015 1021 snapshotlimit = revinfo.textlen >> snapshotdepth
1022 if debug_search:
1023 msg = b"DBG-DELTAS-SEARCH: projected-lower-size=%d\n"
1024 msg %= lowestrealisticdeltalen
1025 self._write_debug(msg)
1016 1026 if snapshotlimit < lowestrealisticdeltalen:
1027 if debug_search:
1028 msg = b"DBG-DELTAS-SEARCH: DISCARDED (snapshot limit)\n"
1029 self._write_debug(msg)
1017 1030 return None
1018 1031 if revlog.length(base) < lowestrealisticdeltalen:
1032 if debug_search:
1033 msg = b"DBG-DELTAS-SEARCH: DISCARDED (prev size)\n"
1034 self._write_debug(msg)
1019 1035 return None
1020 1036 header, data = revlog.compress(delta)
1021 1037 deltalen = len(header) + len(data)
@@ -1090,6 +1106,8 b' class deltacomputer:'
1090 1106 if self._write_debug is not None:
1091 1107 start = util.timer()
1092 1108
1109 debug_search = self._write_debug is not None and self._debug_search
1110
1093 1111 # count the number of different delta we tried (for debug purpose)
1094 1112 dbg_try_count = 0
1095 1113 # count the number of "search round" we did. (for debug purpose)
@@ -1113,6 +1131,10 b' class deltacomputer:'
1113 1131 p2_chain_len = revlog._chaininfo(p2r)[0]
1114 1132 else:
1115 1133 p2_chain_len = -1
1134 if debug_search:
1135 msg = b"DBG-DELTAS-SEARCH: SEARCH rev=%d\n"
1136 msg %= target_rev
1137 self._write_debug(msg)
1116 1138
1117 1139 groups = _candidategroups(
1118 1140 self.revlog, revinfo.textlen, p1r, p2r, cachedelta
@@ -1120,21 +1142,93 b' class deltacomputer:'
1120 1142 candidaterevs = next(groups)
1121 1143 while candidaterevs is not None:
1122 1144 dbg_try_rounds += 1
1145 if debug_search:
1146 prev = None
1147 if deltainfo is not None:
1148 prev = deltainfo.base
1149
1150 if p1 in candidaterevs or p2 in candidaterevs:
1151 round_type = b"parents"
1152 elif prev is not None and all(c < prev for c in candidaterevs):
1153 round_type = b"refine-down"
1154 elif prev is not None and all(c > prev for c in candidaterevs):
1155 round_type = b"refine-up"
1156 else:
1157 round_type = b"search-down"
1158 msg = b"DBG-DELTAS-SEARCH: ROUND #%d - %d candidates - %s\n"
1159 msg %= (dbg_try_rounds, len(candidaterevs), round_type)
1160 self._write_debug(msg)
1123 1161 nominateddeltas = []
1124 1162 if deltainfo is not None:
1163 if debug_search:
1164 msg = (
1165 b"DBG-DELTAS-SEARCH: CONTENDER: rev=%d - length=%d\n"
1166 )
1167 msg %= (deltainfo.base, deltainfo.deltalen)
1168 self._write_debug(msg)
1125 1169 # if we already found a good delta,
1126 1170 # challenge it against refined candidates
1127 1171 nominateddeltas.append(deltainfo)
1128 1172 for candidaterev in candidaterevs:
1173 if debug_search:
1174 msg = b"DBG-DELTAS-SEARCH: CANDIDATE: rev=%d\n"
1175 msg %= candidaterev
1176 self._write_debug(msg)
1177 candidate_type = None
1178 if candidaterev == p1:
1179 candidate_type = b"p1"
1180 elif candidaterev == p2:
1181 candidate_type = b"p2"
1182 elif self.revlog.issnapshot(candidaterev):
1183 candidate_type = b"snapshot-%d"
1184 candidate_type %= self.revlog.snapshotdepth(
1185 candidaterev
1186 )
1187
1188 if candidate_type is not None:
1189 msg = b"DBG-DELTAS-SEARCH: type=%s\n"
1190 msg %= candidate_type
1191 self._write_debug(msg)
1192 msg = b"DBG-DELTAS-SEARCH: size=%d\n"
1193 msg %= self.revlog.length(candidaterev)
1194 self._write_debug(msg)
1195 msg = b"DBG-DELTAS-SEARCH: base=%d\n"
1196 msg %= self.revlog.deltaparent(candidaterev)
1197 self._write_debug(msg)
1129 1198 if candidaterev in excluded_bases:
1199 if debug_search:
1200 msg = b"DBG-DELTAS-SEARCH: EXCLUDED\n"
1201 self._write_debug(msg)
1130 1202 continue
1131 1203 if candidaterev >= target_rev:
1204 if debug_search:
1205 msg = b"DBG-DELTAS-SEARCH: TOO-HIGH\n"
1206 self._write_debug(msg)
1132 1207 continue
1133 1208 dbg_try_count += 1
1209
1210 if debug_search:
1211 delta_start = util.timer()
1134 1212 candidatedelta = self._builddeltainfo(revinfo, candidaterev, fh)
1213 if debug_search:
1214 delta_end = util.timer()
1215 msg = b"DBG-DELTAS-SEARCH: delta-search-time=%f\n"
1216 msg %= delta_end - delta_start
1217 self._write_debug(msg)
1135 1218 if candidatedelta is not None:
1136 1219 if isgooddeltainfo(self.revlog, candidatedelta, revinfo):
1220 if debug_search:
1221 msg = b"DBG-DELTAS-SEARCH: DELTA: length=%d (GOOD)\n"
1222 msg %= candidatedelta.deltalen
1223 self._write_debug(msg)
1137 1224 nominateddeltas.append(candidatedelta)
1225 elif debug_search:
1226 msg = b"DBG-DELTAS-SEARCH: DELTA: length=%d (BAD)\n"
1227 msg %= candidatedelta.deltalen
1228 self._write_debug(msg)
1229 elif debug_search:
1230 msg = b"DBG-DELTAS-SEARCH: NO-DELTA\n"
1231 self._write_debug(msg)
1138 1232 if nominateddeltas:
1139 1233 deltainfo = min(nominateddeltas, key=lambda x: x.deltalen)
1140 1234 if deltainfo is not None:
@@ -1145,7 +1239,7 b' class deltacomputer:'
1145 1239 if deltainfo is None:
1146 1240 dbg_type = b"full"
1147 1241 deltainfo = self._fullsnapshotinfo(fh, revinfo, target_rev)
1148 elif deltainfo.snapshotdepth:
1242 elif deltainfo.snapshotdepth: # pytype: disable=attribute-error
1149 1243 dbg_type = b"snapshot"
1150 1244 else:
1151 1245 dbg_type = b"delta"
@@ -1161,8 +1255,13 b' class deltacomputer:'
1161 1255 'p1-chain-len': p1_chain_len,
1162 1256 'p2-chain-len': p2_chain_len,
1163 1257 }
1164 if deltainfo.snapshotdepth is not None:
1165 dbg['snapshot-depth'] = deltainfo.snapshotdepth
1258 if (
1259 deltainfo.snapshotdepth # pytype: disable=attribute-error
1260 is not None
1261 ):
1262 dbg[
1263 'snapshot-depth'
1264 ] = deltainfo.snapshotdepth # pytype: disable=attribute-error
1166 1265 else:
1167 1266 dbg['snapshot-depth'] = 0
1168 1267 target_revlog = b"UNKNOWN"
@@ -74,6 +74,7 b' Do not show debug commands if there are '
74 74
75 75 Show debug commands if there are no other candidates
76 76 $ hg debugcomplete debug
77 debug-delta-find
77 78 debug-repair-issue6528
78 79 debugancestor
79 80 debugantivirusrunning
@@ -267,6 +268,7 b' Show all commands + options'
267 268 config: untrusted, exp-all-known, edit, local, source, shared, non-shared, global, template
268 269 continue: dry-run
269 270 copy: forget, after, at-rev, force, include, exclude, dry-run
271 debug-delta-find: changelog, manifest, dir, template
270 272 debug-repair-issue6528: to-report, from-report, paranoid, dry-run
271 273 debugancestor:
272 274 debugantivirusrunning:
@@ -978,6 +978,8 b' Test list of internal help commands'
978 978 $ hg help debug
979 979 debug commands (internal and unsupported):
980 980
981 debug-delta-find
982 display the computation to get to a valid delta for storing REV
981 983 debug-repair-issue6528
982 984 find affected revisions and repair them. See issue6528 for more
983 985 details.
@@ -149,4 +149,46 b' repeatedly while some of it changes rare'
149 149 deltas against p2 : 63 ( 1.36%)
150 150 deltas against other : 0 ( 0.00%)
151 151
152
153 Test `debug-delta-find`
154 -----------------------
155
156 $ ls -1
157 SPARSE-REVLOG-TEST-FILE
158 $ hg debugdeltachain SPARSE-REVLOG-TEST-FILE | grep other | tail -1
159 4971 3 5 4930 other 19179 346472 427596 1.23414 15994877 15567281 36.40652 427596 179288 1.00000 5
160 $ hg debug-delta-find SPARSE-REVLOG-TEST-FILE 4971
161 DBG-DELTAS-SEARCH: SEARCH rev=4971
162 DBG-DELTAS-SEARCH: ROUND #1 - 2 candidates - search-down
163 DBG-DELTAS-SEARCH: CANDIDATE: rev=4962
164 DBG-DELTAS-SEARCH: type=snapshot-4
165 DBG-DELTAS-SEARCH: size=18296
166 DBG-DELTAS-SEARCH: base=4930
167 DBG-DELTAS-SEARCH: uncompressed-delta-size=30377
168 DBG-DELTAS-SEARCH: delta-search-time=* (glob)
169 DBG-DELTAS-SEARCH: DELTA: length=16872 (BAD)
170 DBG-DELTAS-SEARCH: CANDIDATE: rev=4971
171 DBG-DELTAS-SEARCH: type=snapshot-4
172 DBG-DELTAS-SEARCH: size=19179
173 DBG-DELTAS-SEARCH: base=4930
174 DBG-DELTAS-SEARCH: TOO-HIGH
175 DBG-DELTAS-SEARCH: ROUND #2 - 1 candidates - search-down
176 DBG-DELTAS-SEARCH: CANDIDATE: rev=4930
177 DBG-DELTAS-SEARCH: type=snapshot-3
178 DBG-DELTAS-SEARCH: size=39228
179 DBG-DELTAS-SEARCH: base=4799
180 DBG-DELTAS-SEARCH: uncompressed-delta-size=33050
181 DBG-DELTAS-SEARCH: delta-search-time=* (glob)
182 DBG-DELTAS-SEARCH: DELTA: length=19179 (GOOD)
183 DBG-DELTAS-SEARCH: ROUND #3 - 1 candidates - refine-down
184 DBG-DELTAS-SEARCH: CONTENDER: rev=4930 - length=19179
185 DBG-DELTAS-SEARCH: CANDIDATE: rev=4799
186 DBG-DELTAS-SEARCH: type=snapshot-2
187 DBG-DELTAS-SEARCH: size=50213
188 DBG-DELTAS-SEARCH: base=4623
189 DBG-DELTAS-SEARCH: uncompressed-delta-size=82661
190 DBG-DELTAS-SEARCH: delta-search-time=* (glob)
191 DBG-DELTAS-SEARCH: DELTA: length=49132 (BAD)
192 DBG-DELTAS: FILELOG:SPARSE-REVLOG-TEST-FILE: rev=4971: search-rounds=3 try-count=3 - delta-type=snapshot snap-depth=4 - p1-chain-length=15 p2-chain-length=-1 - duration=* (glob)
193
152 194 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now