##// END OF EJS Templates
debug-revlog: keep the revlog open for the analysis duration...
marmoute -
r51910:edc44ab7 default
parent child Browse files
Show More
@@ -1,709 +1,712 b''
1 # revlogutils/debug.py - utility used for revlog debuging
1 # revlogutils/debug.py - utility used for revlog debuging
2 #
2 #
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
4 # Copyright 2022 Octobus <contact@octobus.net>
4 # Copyright 2022 Octobus <contact@octobus.net>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 import collections
9 import collections
10 import string
10 import string
11
11
12 from .. import (
12 from .. import (
13 mdiff,
13 mdiff,
14 node as nodemod,
14 node as nodemod,
15 revlogutils,
15 revlogutils,
16 )
16 )
17
17
18 from . import (
18 from . import (
19 constants,
19 constants,
20 deltas as deltautil,
20 deltas as deltautil,
21 )
21 )
22
22
23 INDEX_ENTRY_DEBUG_COLUMN = []
23 INDEX_ENTRY_DEBUG_COLUMN = []
24
24
25 NODE_SIZE = object()
25 NODE_SIZE = object()
26
26
27
27
28 class _column_base:
28 class _column_base:
29 """constains the definition of a revlog column
29 """constains the definition of a revlog column
30
30
31 name: the column header,
31 name: the column header,
32 value_func: the function called to get a value,
32 value_func: the function called to get a value,
33 size: the width of the column,
33 size: the width of the column,
34 verbose_only: only include the column in verbose mode.
34 verbose_only: only include the column in verbose mode.
35 """
35 """
36
36
37 def __init__(self, name, value_func, size=None, verbose=False):
37 def __init__(self, name, value_func, size=None, verbose=False):
38 self.name = name
38 self.name = name
39 self.value_func = value_func
39 self.value_func = value_func
40 if size is not NODE_SIZE:
40 if size is not NODE_SIZE:
41 if size is None:
41 if size is None:
42 size = 8 # arbitrary default
42 size = 8 # arbitrary default
43 size = max(len(name), size)
43 size = max(len(name), size)
44 self._size = size
44 self._size = size
45 self.verbose_only = verbose
45 self.verbose_only = verbose
46
46
47 def get_size(self, node_size):
47 def get_size(self, node_size):
48 if self._size is NODE_SIZE:
48 if self._size is NODE_SIZE:
49 return node_size
49 return node_size
50 else:
50 else:
51 return self._size
51 return self._size
52
52
53
53
54 def debug_column(name, size=None, verbose=False):
54 def debug_column(name, size=None, verbose=False):
55 """decorated function is registered as a column
55 """decorated function is registered as a column
56
56
57 name: the name of the column,
57 name: the name of the column,
58 size: the expected size of the column.
58 size: the expected size of the column.
59 """
59 """
60
60
61 def register(func):
61 def register(func):
62 entry = _column_base(
62 entry = _column_base(
63 name=name,
63 name=name,
64 value_func=func,
64 value_func=func,
65 size=size,
65 size=size,
66 verbose=verbose,
66 verbose=verbose,
67 )
67 )
68 INDEX_ENTRY_DEBUG_COLUMN.append(entry)
68 INDEX_ENTRY_DEBUG_COLUMN.append(entry)
69 return entry
69 return entry
70
70
71 return register
71 return register
72
72
73
73
74 @debug_column(b"rev", size=6)
74 @debug_column(b"rev", size=6)
75 def _rev(index, rev, entry, hexfn):
75 def _rev(index, rev, entry, hexfn):
76 return b"%d" % rev
76 return b"%d" % rev
77
77
78
78
79 @debug_column(b"rank", size=6, verbose=True)
79 @debug_column(b"rank", size=6, verbose=True)
80 def rank(index, rev, entry, hexfn):
80 def rank(index, rev, entry, hexfn):
81 return b"%d" % entry[constants.ENTRY_RANK]
81 return b"%d" % entry[constants.ENTRY_RANK]
82
82
83
83
84 @debug_column(b"linkrev", size=6)
84 @debug_column(b"linkrev", size=6)
85 def _linkrev(index, rev, entry, hexfn):
85 def _linkrev(index, rev, entry, hexfn):
86 return b"%d" % entry[constants.ENTRY_LINK_REV]
86 return b"%d" % entry[constants.ENTRY_LINK_REV]
87
87
88
88
89 @debug_column(b"nodeid", size=NODE_SIZE)
89 @debug_column(b"nodeid", size=NODE_SIZE)
90 def _nodeid(index, rev, entry, hexfn):
90 def _nodeid(index, rev, entry, hexfn):
91 return hexfn(entry[constants.ENTRY_NODE_ID])
91 return hexfn(entry[constants.ENTRY_NODE_ID])
92
92
93
93
94 @debug_column(b"p1-rev", size=6, verbose=True)
94 @debug_column(b"p1-rev", size=6, verbose=True)
95 def _p1_rev(index, rev, entry, hexfn):
95 def _p1_rev(index, rev, entry, hexfn):
96 return b"%d" % entry[constants.ENTRY_PARENT_1]
96 return b"%d" % entry[constants.ENTRY_PARENT_1]
97
97
98
98
99 @debug_column(b"p1-nodeid", size=NODE_SIZE)
99 @debug_column(b"p1-nodeid", size=NODE_SIZE)
100 def _p1_node(index, rev, entry, hexfn):
100 def _p1_node(index, rev, entry, hexfn):
101 parent = entry[constants.ENTRY_PARENT_1]
101 parent = entry[constants.ENTRY_PARENT_1]
102 p_entry = index[parent]
102 p_entry = index[parent]
103 return hexfn(p_entry[constants.ENTRY_NODE_ID])
103 return hexfn(p_entry[constants.ENTRY_NODE_ID])
104
104
105
105
106 @debug_column(b"p2-rev", size=6, verbose=True)
106 @debug_column(b"p2-rev", size=6, verbose=True)
107 def _p2_rev(index, rev, entry, hexfn):
107 def _p2_rev(index, rev, entry, hexfn):
108 return b"%d" % entry[constants.ENTRY_PARENT_2]
108 return b"%d" % entry[constants.ENTRY_PARENT_2]
109
109
110
110
111 @debug_column(b"p2-nodeid", size=NODE_SIZE)
111 @debug_column(b"p2-nodeid", size=NODE_SIZE)
112 def _p2_node(index, rev, entry, hexfn):
112 def _p2_node(index, rev, entry, hexfn):
113 parent = entry[constants.ENTRY_PARENT_2]
113 parent = entry[constants.ENTRY_PARENT_2]
114 p_entry = index[parent]
114 p_entry = index[parent]
115 return hexfn(p_entry[constants.ENTRY_NODE_ID])
115 return hexfn(p_entry[constants.ENTRY_NODE_ID])
116
116
117
117
118 @debug_column(b"full-size", size=20, verbose=True)
118 @debug_column(b"full-size", size=20, verbose=True)
119 def full_size(index, rev, entry, hexfn):
119 def full_size(index, rev, entry, hexfn):
120 return b"%d" % entry[constants.ENTRY_DATA_UNCOMPRESSED_LENGTH]
120 return b"%d" % entry[constants.ENTRY_DATA_UNCOMPRESSED_LENGTH]
121
121
122
122
123 @debug_column(b"delta-base", size=6, verbose=True)
123 @debug_column(b"delta-base", size=6, verbose=True)
124 def delta_base(index, rev, entry, hexfn):
124 def delta_base(index, rev, entry, hexfn):
125 return b"%d" % entry[constants.ENTRY_DELTA_BASE]
125 return b"%d" % entry[constants.ENTRY_DELTA_BASE]
126
126
127
127
128 @debug_column(b"flags", size=2, verbose=True)
128 @debug_column(b"flags", size=2, verbose=True)
129 def flags(index, rev, entry, hexfn):
129 def flags(index, rev, entry, hexfn):
130 field = entry[constants.ENTRY_DATA_OFFSET]
130 field = entry[constants.ENTRY_DATA_OFFSET]
131 field &= 0xFFFF
131 field &= 0xFFFF
132 return b"%d" % field
132 return b"%d" % field
133
133
134
134
135 @debug_column(b"comp-mode", size=4, verbose=True)
135 @debug_column(b"comp-mode", size=4, verbose=True)
136 def compression_mode(index, rev, entry, hexfn):
136 def compression_mode(index, rev, entry, hexfn):
137 return b"%d" % entry[constants.ENTRY_DATA_COMPRESSION_MODE]
137 return b"%d" % entry[constants.ENTRY_DATA_COMPRESSION_MODE]
138
138
139
139
140 @debug_column(b"data-offset", size=20, verbose=True)
140 @debug_column(b"data-offset", size=20, verbose=True)
141 def data_offset(index, rev, entry, hexfn):
141 def data_offset(index, rev, entry, hexfn):
142 field = entry[constants.ENTRY_DATA_OFFSET]
142 field = entry[constants.ENTRY_DATA_OFFSET]
143 field >>= 16
143 field >>= 16
144 return b"%d" % field
144 return b"%d" % field
145
145
146
146
147 @debug_column(b"chunk-size", size=10, verbose=True)
147 @debug_column(b"chunk-size", size=10, verbose=True)
148 def data_chunk_size(index, rev, entry, hexfn):
148 def data_chunk_size(index, rev, entry, hexfn):
149 return b"%d" % entry[constants.ENTRY_DATA_COMPRESSED_LENGTH]
149 return b"%d" % entry[constants.ENTRY_DATA_COMPRESSED_LENGTH]
150
150
151
151
152 @debug_column(b"sd-comp-mode", size=7, verbose=True)
152 @debug_column(b"sd-comp-mode", size=7, verbose=True)
153 def sidedata_compression_mode(index, rev, entry, hexfn):
153 def sidedata_compression_mode(index, rev, entry, hexfn):
154 compression = entry[constants.ENTRY_SIDEDATA_COMPRESSION_MODE]
154 compression = entry[constants.ENTRY_SIDEDATA_COMPRESSION_MODE]
155 if compression == constants.COMP_MODE_PLAIN:
155 if compression == constants.COMP_MODE_PLAIN:
156 return b"plain"
156 return b"plain"
157 elif compression == constants.COMP_MODE_DEFAULT:
157 elif compression == constants.COMP_MODE_DEFAULT:
158 return b"default"
158 return b"default"
159 elif compression == constants.COMP_MODE_INLINE:
159 elif compression == constants.COMP_MODE_INLINE:
160 return b"inline"
160 return b"inline"
161 else:
161 else:
162 return b"%d" % compression
162 return b"%d" % compression
163
163
164
164
165 @debug_column(b"sidedata-offset", size=20, verbose=True)
165 @debug_column(b"sidedata-offset", size=20, verbose=True)
166 def sidedata_offset(index, rev, entry, hexfn):
166 def sidedata_offset(index, rev, entry, hexfn):
167 return b"%d" % entry[constants.ENTRY_SIDEDATA_OFFSET]
167 return b"%d" % entry[constants.ENTRY_SIDEDATA_OFFSET]
168
168
169
169
170 @debug_column(b"sd-chunk-size", size=10, verbose=True)
170 @debug_column(b"sd-chunk-size", size=10, verbose=True)
171 def sidedata_chunk_size(index, rev, entry, hexfn):
171 def sidedata_chunk_size(index, rev, entry, hexfn):
172 return b"%d" % entry[constants.ENTRY_SIDEDATA_COMPRESSED_LENGTH]
172 return b"%d" % entry[constants.ENTRY_SIDEDATA_COMPRESSED_LENGTH]
173
173
174
174
175 def debug_index(
175 def debug_index(
176 ui,
176 ui,
177 repo,
177 repo,
178 formatter,
178 formatter,
179 revlog,
179 revlog,
180 full_node,
180 full_node,
181 ):
181 ):
182 """display index data for a revlog"""
182 """display index data for a revlog"""
183 if full_node:
183 if full_node:
184 hexfn = nodemod.hex
184 hexfn = nodemod.hex
185 else:
185 else:
186 hexfn = nodemod.short
186 hexfn = nodemod.short
187
187
188 idlen = 12
188 idlen = 12
189 for i in revlog:
189 for i in revlog:
190 idlen = len(hexfn(revlog.node(i)))
190 idlen = len(hexfn(revlog.node(i)))
191 break
191 break
192
192
193 fm = formatter
193 fm = formatter
194
194
195 header_pieces = []
195 header_pieces = []
196 for column in INDEX_ENTRY_DEBUG_COLUMN:
196 for column in INDEX_ENTRY_DEBUG_COLUMN:
197 if column.verbose_only and not ui.verbose:
197 if column.verbose_only and not ui.verbose:
198 continue
198 continue
199 size = column.get_size(idlen)
199 size = column.get_size(idlen)
200 name = column.name
200 name = column.name
201 header_pieces.append(name.rjust(size))
201 header_pieces.append(name.rjust(size))
202
202
203 fm.plain(b' '.join(header_pieces) + b'\n')
203 fm.plain(b' '.join(header_pieces) + b'\n')
204
204
205 index = revlog.index
205 index = revlog.index
206
206
207 for rev in revlog:
207 for rev in revlog:
208 fm.startitem()
208 fm.startitem()
209 entry = index[rev]
209 entry = index[rev]
210 first = True
210 first = True
211 for column in INDEX_ENTRY_DEBUG_COLUMN:
211 for column in INDEX_ENTRY_DEBUG_COLUMN:
212 if column.verbose_only and not ui.verbose:
212 if column.verbose_only and not ui.verbose:
213 continue
213 continue
214 if not first:
214 if not first:
215 fm.plain(b' ')
215 fm.plain(b' ')
216 first = False
216 first = False
217
217
218 size = column.get_size(idlen)
218 size = column.get_size(idlen)
219 value = column.value_func(index, rev, entry, hexfn)
219 value = column.value_func(index, rev, entry, hexfn)
220 display = b"%%%ds" % size
220 display = b"%%%ds" % size
221 fm.write(column.name, display, value)
221 fm.write(column.name, display, value)
222 fm.plain(b'\n')
222 fm.plain(b'\n')
223
223
224 fm.end()
224 fm.end()
225
225
226
226
227 def dump(ui, revlog):
227 def dump(ui, revlog):
228 """perform the work for `hg debugrevlog --dump"""
228 """perform the work for `hg debugrevlog --dump"""
229 # XXX seems redundant with debug index ?
229 # XXX seems redundant with debug index ?
230 r = revlog
230 r = revlog
231 numrevs = len(r)
231 numrevs = len(r)
232 ui.write(
232 ui.write(
233 (
233 (
234 b"# rev p1rev p2rev start end deltastart base p1 p2"
234 b"# rev p1rev p2rev start end deltastart base p1 p2"
235 b" rawsize totalsize compression heads chainlen\n"
235 b" rawsize totalsize compression heads chainlen\n"
236 )
236 )
237 )
237 )
238 ts = 0
238 ts = 0
239 heads = set()
239 heads = set()
240
240
241 for rev in range(numrevs):
241 for rev in range(numrevs):
242 dbase = r.deltaparent(rev)
242 dbase = r.deltaparent(rev)
243 if dbase == -1:
243 if dbase == -1:
244 dbase = rev
244 dbase = rev
245 cbase = r.chainbase(rev)
245 cbase = r.chainbase(rev)
246 clen = r.chainlen(rev)
246 clen = r.chainlen(rev)
247 p1, p2 = r.parentrevs(rev)
247 p1, p2 = r.parentrevs(rev)
248 rs = r.rawsize(rev)
248 rs = r.rawsize(rev)
249 ts = ts + rs
249 ts = ts + rs
250 heads -= set(r.parentrevs(rev))
250 heads -= set(r.parentrevs(rev))
251 heads.add(rev)
251 heads.add(rev)
252 try:
252 try:
253 compression = ts / r.end(rev)
253 compression = ts / r.end(rev)
254 except ZeroDivisionError:
254 except ZeroDivisionError:
255 compression = 0
255 compression = 0
256 ui.write(
256 ui.write(
257 b"%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
257 b"%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
258 b"%11d %5d %8d\n"
258 b"%11d %5d %8d\n"
259 % (
259 % (
260 rev,
260 rev,
261 p1,
261 p1,
262 p2,
262 p2,
263 r.start(rev),
263 r.start(rev),
264 r.end(rev),
264 r.end(rev),
265 r.start(dbase),
265 r.start(dbase),
266 r.start(cbase),
266 r.start(cbase),
267 r.start(p1),
267 r.start(p1),
268 r.start(p2),
268 r.start(p2),
269 rs,
269 rs,
270 ts,
270 ts,
271 compression,
271 compression,
272 len(heads),
272 len(heads),
273 clen,
273 clen,
274 )
274 )
275 )
275 )
276
276
277
277
278 def debug_revlog(ui, revlog):
278 def debug_revlog(ui, revlog):
279 """code for `hg debugrevlog`"""
279 """code for `hg debugrevlog`"""
280 r = revlog
280 r = revlog
281 format = r._format_version
281 format = r._format_version
282 v = r._format_flags
282 v = r._format_flags
283 flags = []
283 flags = []
284 gdelta = False
284 gdelta = False
285 if v & constants.FLAG_INLINE_DATA:
285 if v & constants.FLAG_INLINE_DATA:
286 flags.append(b'inline')
286 flags.append(b'inline')
287 if v & constants.FLAG_GENERALDELTA:
287 if v & constants.FLAG_GENERALDELTA:
288 gdelta = True
288 gdelta = True
289 flags.append(b'generaldelta')
289 flags.append(b'generaldelta')
290 if not flags:
290 if not flags:
291 flags = [b'(none)']
291 flags = [b'(none)']
292
292
293 ### the total size of stored content if incompressed.
293 ### the total size of stored content if incompressed.
294 full_text_total_size = 0
294 full_text_total_size = 0
295 ### tracks merge vs single parent
295 ### tracks merge vs single parent
296 nummerges = 0
296 nummerges = 0
297
297
298 ### tracks ways the "delta" are build
298 ### tracks ways the "delta" are build
299 # nodelta
299 # nodelta
300 numempty = 0
300 numempty = 0
301 numemptytext = 0
301 numemptytext = 0
302 numemptydelta = 0
302 numemptydelta = 0
303 # full file content
303 # full file content
304 numfull = 0
304 numfull = 0
305 # intermediate snapshot against a prior snapshot
305 # intermediate snapshot against a prior snapshot
306 numsemi = 0
306 numsemi = 0
307 # snapshot count per depth
307 # snapshot count per depth
308 numsnapdepth = collections.defaultdict(lambda: 0)
308 numsnapdepth = collections.defaultdict(lambda: 0)
309 # number of snapshots with a non-ancestor delta
309 # number of snapshots with a non-ancestor delta
310 numsnapdepth_nad = collections.defaultdict(lambda: 0)
310 numsnapdepth_nad = collections.defaultdict(lambda: 0)
311 # delta against previous revision
311 # delta against previous revision
312 numprev = 0
312 numprev = 0
313 # delta against prev, where prev is a non-ancestor
313 # delta against prev, where prev is a non-ancestor
314 numprev_nad = 0
314 numprev_nad = 0
315 # delta against first or second parent (not prev)
315 # delta against first or second parent (not prev)
316 nump1 = 0
316 nump1 = 0
317 nump2 = 0
317 nump2 = 0
318 # delta against neither prev nor parents
318 # delta against neither prev nor parents
319 numother = 0
319 numother = 0
320 # delta against other that is a non-ancestor
320 # delta against other that is a non-ancestor
321 numother_nad = 0
321 numother_nad = 0
322 # delta against prev that are also first or second parent
322 # delta against prev that are also first or second parent
323 # (details of `numprev`)
323 # (details of `numprev`)
324 nump1prev = 0
324 nump1prev = 0
325 nump2prev = 0
325 nump2prev = 0
326
326
327 # data about delta chain of each revs
327 # data about delta chain of each revs
328 chainlengths = []
328 chainlengths = []
329 chainbases = []
329 chainbases = []
330 chainspans = []
330 chainspans = []
331
331
332 # data about each revision
332 # data about each revision
333 datasize = [None, 0, 0]
333 datasize = [None, 0, 0]
334 fullsize = [None, 0, 0]
334 fullsize = [None, 0, 0]
335 semisize = [None, 0, 0]
335 semisize = [None, 0, 0]
336 # snapshot count per depth
336 # snapshot count per depth
337 snapsizedepth = collections.defaultdict(lambda: [None, 0, 0])
337 snapsizedepth = collections.defaultdict(lambda: [None, 0, 0])
338 deltasize = [None, 0, 0]
338 deltasize = [None, 0, 0]
339 chunktypecounts = {}
339 chunktypecounts = {}
340 chunktypesizes = {}
340 chunktypesizes = {}
341
341
342 def addsize(size, l):
342 def addsize(size, l):
343 if l[0] is None or size < l[0]:
343 if l[0] is None or size < l[0]:
344 l[0] = size
344 l[0] = size
345 if size > l[1]:
345 if size > l[1]:
346 l[1] = size
346 l[1] = size
347 l[2] += size
347 l[2] += size
348
348
349 numrevs = len(r)
349 with r.reading():
350 for rev in range(numrevs):
350 numrevs = len(r)
351 p1, p2 = r.parentrevs(rev)
351 for rev in range(numrevs):
352 delta = r.deltaparent(rev)
352 p1, p2 = r.parentrevs(rev)
353 if format > 0:
353 delta = r.deltaparent(rev)
354 s = r.rawsize(rev)
354 if format > 0:
355 full_text_total_size += s
355 s = r.rawsize(rev)
356 addsize(s, datasize)
356 full_text_total_size += s
357 if p2 != nodemod.nullrev:
357 addsize(s, datasize)
358 nummerges += 1
358 if p2 != nodemod.nullrev:
359 size = r.length(rev)
359 nummerges += 1
360 if delta == nodemod.nullrev:
360 size = r.length(rev)
361 chainlengths.append(0)
361 if delta == nodemod.nullrev:
362 chainbases.append(r.start(rev))
362 chainlengths.append(0)
363 chainspans.append(size)
363 chainbases.append(r.start(rev))
364 if size == 0:
364 chainspans.append(size)
365 numempty += 1
365 if size == 0:
366 numemptytext += 1
366 numempty += 1
367 numemptytext += 1
368 else:
369 numfull += 1
370 numsnapdepth[0] += 1
371 addsize(size, fullsize)
372 addsize(size, snapsizedepth[0])
367 else:
373 else:
368 numfull += 1
374 nad = (
369 numsnapdepth[0] += 1
375 delta != p1
370 addsize(size, fullsize)
376 and delta != p2
371 addsize(size, snapsizedepth[0])
377 and not r.isancestorrev(delta, rev)
372 else:
378 )
373 nad = (
379 chainlengths.append(chainlengths[delta] + 1)
374 delta != p1 and delta != p2 and not r.isancestorrev(delta, rev)
380 baseaddr = chainbases[delta]
375 )
381 revaddr = r.start(rev)
376 chainlengths.append(chainlengths[delta] + 1)
382 chainbases.append(baseaddr)
377 baseaddr = chainbases[delta]
383 chainspans.append((revaddr - baseaddr) + size)
378 revaddr = r.start(rev)
384 if size == 0:
379 chainbases.append(baseaddr)
385 numempty += 1
380 chainspans.append((revaddr - baseaddr) + size)
386 numemptydelta += 1
381 if size == 0:
387 elif r.issnapshot(rev):
382 numempty += 1
388 addsize(size, semisize)
383 numemptydelta += 1
389 numsemi += 1
384 elif r.issnapshot(rev):
390 depth = r.snapshotdepth(rev)
385 addsize(size, semisize)
391 numsnapdepth[depth] += 1
386 numsemi += 1
392 if nad:
387 depth = r.snapshotdepth(rev)
393 numsnapdepth_nad[depth] += 1
388 numsnapdepth[depth] += 1
394 addsize(size, snapsizedepth[depth])
389 if nad:
395 else:
390 numsnapdepth_nad[depth] += 1
396 addsize(size, deltasize)
391 addsize(size, snapsizedepth[depth])
397 if delta == rev - 1:
398 numprev += 1
399 if delta == p1:
400 nump1prev += 1
401 elif delta == p2:
402 nump2prev += 1
403 elif nad:
404 numprev_nad += 1
405 elif delta == p1:
406 nump1 += 1
407 elif delta == p2:
408 nump2 += 1
409 elif delta != nodemod.nullrev:
410 numother += 1
411 numother_nad += 1
412
413 # Obtain data on the raw chunks in the revlog.
414 if hasattr(r, '_getsegmentforrevs'):
415 segment = r._getsegmentforrevs(rev, rev)[1]
392 else:
416 else:
393 addsize(size, deltasize)
417 segment = r._revlog._getsegmentforrevs(rev, rev)[1]
394 if delta == rev - 1:
418 if segment:
395 numprev += 1
419 chunktype = bytes(segment[0:1])
396 if delta == p1:
420 else:
397 nump1prev += 1
421 chunktype = b'empty'
398 elif delta == p2:
399 nump2prev += 1
400 elif nad:
401 numprev_nad += 1
402 elif delta == p1:
403 nump1 += 1
404 elif delta == p2:
405 nump2 += 1
406 elif delta != nodemod.nullrev:
407 numother += 1
408 numother_nad += 1
409
422
410 # Obtain data on the raw chunks in the revlog.
423 if chunktype not in chunktypecounts:
411 if hasattr(r, '_getsegmentforrevs'):
424 chunktypecounts[chunktype] = 0
412 segment = r._getsegmentforrevs(rev, rev)[1]
425 chunktypesizes[chunktype] = 0
413 else:
414 segment = r._revlog._getsegmentforrevs(rev, rev)[1]
415 if segment:
416 chunktype = bytes(segment[0:1])
417 else:
418 chunktype = b'empty'
419
426
420 if chunktype not in chunktypecounts:
427 chunktypecounts[chunktype] += 1
421 chunktypecounts[chunktype] = 0
428 chunktypesizes[chunktype] += size
422 chunktypesizes[chunktype] = 0
423
424 chunktypecounts[chunktype] += 1
425 chunktypesizes[chunktype] += size
426
429
427 # Adjust size min value for empty cases
430 # Adjust size min value for empty cases
428 for size in (datasize, fullsize, semisize, deltasize):
431 for size in (datasize, fullsize, semisize, deltasize):
429 if size[0] is None:
432 if size[0] is None:
430 size[0] = 0
433 size[0] = 0
431
434
432 numdeltas = numrevs - numfull - numempty - numsemi
435 numdeltas = numrevs - numfull - numempty - numsemi
433 numoprev = numprev - nump1prev - nump2prev - numprev_nad
436 numoprev = numprev - nump1prev - nump2prev - numprev_nad
434 num_other_ancestors = numother - numother_nad
437 num_other_ancestors = numother - numother_nad
435 totalrawsize = datasize[2]
438 totalrawsize = datasize[2]
436 datasize[2] /= numrevs
439 datasize[2] /= numrevs
437 fulltotal = fullsize[2]
440 fulltotal = fullsize[2]
438 if numfull == 0:
441 if numfull == 0:
439 fullsize[2] = 0
442 fullsize[2] = 0
440 else:
443 else:
441 fullsize[2] /= numfull
444 fullsize[2] /= numfull
442 semitotal = semisize[2]
445 semitotal = semisize[2]
443 snaptotal = {}
446 snaptotal = {}
444 if numsemi > 0:
447 if numsemi > 0:
445 semisize[2] /= numsemi
448 semisize[2] /= numsemi
446 for depth in snapsizedepth:
449 for depth in snapsizedepth:
447 snaptotal[depth] = snapsizedepth[depth][2]
450 snaptotal[depth] = snapsizedepth[depth][2]
448 snapsizedepth[depth][2] /= numsnapdepth[depth]
451 snapsizedepth[depth][2] /= numsnapdepth[depth]
449
452
450 deltatotal = deltasize[2]
453 deltatotal = deltasize[2]
451 if numdeltas > 0:
454 if numdeltas > 0:
452 deltasize[2] /= numdeltas
455 deltasize[2] /= numdeltas
453 totalsize = fulltotal + semitotal + deltatotal
456 totalsize = fulltotal + semitotal + deltatotal
454 avgchainlen = sum(chainlengths) / numrevs
457 avgchainlen = sum(chainlengths) / numrevs
455 maxchainlen = max(chainlengths)
458 maxchainlen = max(chainlengths)
456 maxchainspan = max(chainspans)
459 maxchainspan = max(chainspans)
457 compratio = 1
460 compratio = 1
458 if totalsize:
461 if totalsize:
459 compratio = totalrawsize / totalsize
462 compratio = totalrawsize / totalsize
460
463
461 basedfmtstr = b'%%%dd\n'
464 basedfmtstr = b'%%%dd\n'
462 basepcfmtstr = b'%%%dd %s(%%5.2f%%%%)\n'
465 basepcfmtstr = b'%%%dd %s(%%5.2f%%%%)\n'
463
466
464 def dfmtstr(max):
467 def dfmtstr(max):
465 return basedfmtstr % len(str(max))
468 return basedfmtstr % len(str(max))
466
469
467 def pcfmtstr(max, padding=0):
470 def pcfmtstr(max, padding=0):
468 return basepcfmtstr % (len(str(max)), b' ' * padding)
471 return basepcfmtstr % (len(str(max)), b' ' * padding)
469
472
470 def pcfmt(value, total):
473 def pcfmt(value, total):
471 if total:
474 if total:
472 return (value, 100 * float(value) / total)
475 return (value, 100 * float(value) / total)
473 else:
476 else:
474 return value, 100.0
477 return value, 100.0
475
478
476 ui.writenoi18n(b'format : %d\n' % format)
479 ui.writenoi18n(b'format : %d\n' % format)
477 ui.writenoi18n(b'flags : %s\n' % b', '.join(flags))
480 ui.writenoi18n(b'flags : %s\n' % b', '.join(flags))
478
481
479 ui.write(b'\n')
482 ui.write(b'\n')
480 fmt = pcfmtstr(totalsize)
483 fmt = pcfmtstr(totalsize)
481 fmt2 = dfmtstr(totalsize)
484 fmt2 = dfmtstr(totalsize)
482 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
485 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
483 ui.writenoi18n(b' merges : ' + fmt % pcfmt(nummerges, numrevs))
486 ui.writenoi18n(b' merges : ' + fmt % pcfmt(nummerges, numrevs))
484 ui.writenoi18n(
487 ui.writenoi18n(
485 b' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs)
488 b' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs)
486 )
489 )
487 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
490 ui.writenoi18n(b'revisions : ' + fmt2 % numrevs)
488 ui.writenoi18n(b' empty : ' + fmt % pcfmt(numempty, numrevs))
491 ui.writenoi18n(b' empty : ' + fmt % pcfmt(numempty, numrevs))
489 ui.writenoi18n(
492 ui.writenoi18n(
490 b' text : '
493 b' text : '
491 + fmt % pcfmt(numemptytext, numemptytext + numemptydelta)
494 + fmt % pcfmt(numemptytext, numemptytext + numemptydelta)
492 )
495 )
493 ui.writenoi18n(
496 ui.writenoi18n(
494 b' delta : '
497 b' delta : '
495 + fmt % pcfmt(numemptydelta, numemptytext + numemptydelta)
498 + fmt % pcfmt(numemptydelta, numemptytext + numemptydelta)
496 )
499 )
497 ui.writenoi18n(
500 ui.writenoi18n(
498 b' snapshot : ' + fmt % pcfmt(numfull + numsemi, numrevs)
501 b' snapshot : ' + fmt % pcfmt(numfull + numsemi, numrevs)
499 )
502 )
500 for depth in sorted(numsnapdepth):
503 for depth in sorted(numsnapdepth):
501 base = b' lvl-%-3d : ' % depth
504 base = b' lvl-%-3d : ' % depth
502 count = fmt % pcfmt(numsnapdepth[depth], numrevs)
505 count = fmt % pcfmt(numsnapdepth[depth], numrevs)
503 pieces = [base, count]
506 pieces = [base, count]
504 if numsnapdepth_nad[depth]:
507 if numsnapdepth_nad[depth]:
505 pieces[-1] = count = count[:-1] # drop the final '\n'
508 pieces[-1] = count = count[:-1] # drop the final '\n'
506 more = b' non-ancestor-bases: '
509 more = b' non-ancestor-bases: '
507 anc_count = fmt
510 anc_count = fmt
508 anc_count %= pcfmt(numsnapdepth_nad[depth], numsnapdepth[depth])
511 anc_count %= pcfmt(numsnapdepth_nad[depth], numsnapdepth[depth])
509 pieces.append(more)
512 pieces.append(more)
510 pieces.append(anc_count)
513 pieces.append(anc_count)
511 ui.write(b''.join(pieces))
514 ui.write(b''.join(pieces))
512 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
515 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
513 ui.writenoi18n(b'revision size : ' + fmt2 % totalsize)
516 ui.writenoi18n(b'revision size : ' + fmt2 % totalsize)
514 ui.writenoi18n(
517 ui.writenoi18n(
515 b' snapshot : ' + fmt % pcfmt(fulltotal + semitotal, totalsize)
518 b' snapshot : ' + fmt % pcfmt(fulltotal + semitotal, totalsize)
516 )
519 )
517 for depth in sorted(numsnapdepth):
520 for depth in sorted(numsnapdepth):
518 ui.write(
521 ui.write(
519 (b' lvl-%-3d : ' % depth)
522 (b' lvl-%-3d : ' % depth)
520 + fmt % pcfmt(snaptotal[depth], totalsize)
523 + fmt % pcfmt(snaptotal[depth], totalsize)
521 )
524 )
522 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
525 ui.writenoi18n(b' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
523
526
524 letters = string.ascii_letters.encode('ascii')
527 letters = string.ascii_letters.encode('ascii')
525
528
526 def fmtchunktype(chunktype):
529 def fmtchunktype(chunktype):
527 if chunktype == b'empty':
530 if chunktype == b'empty':
528 return b' %s : ' % chunktype
531 return b' %s : ' % chunktype
529 elif chunktype in letters:
532 elif chunktype in letters:
530 return b' 0x%s (%s) : ' % (nodemod.hex(chunktype), chunktype)
533 return b' 0x%s (%s) : ' % (nodemod.hex(chunktype), chunktype)
531 else:
534 else:
532 return b' 0x%s : ' % nodemod.hex(chunktype)
535 return b' 0x%s : ' % nodemod.hex(chunktype)
533
536
534 ui.write(b'\n')
537 ui.write(b'\n')
535 ui.writenoi18n(b'chunks : ' + fmt2 % numrevs)
538 ui.writenoi18n(b'chunks : ' + fmt2 % numrevs)
536 for chunktype in sorted(chunktypecounts):
539 for chunktype in sorted(chunktypecounts):
537 ui.write(fmtchunktype(chunktype))
540 ui.write(fmtchunktype(chunktype))
538 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
541 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
539 ui.writenoi18n(b'chunks size : ' + fmt2 % totalsize)
542 ui.writenoi18n(b'chunks size : ' + fmt2 % totalsize)
540 for chunktype in sorted(chunktypecounts):
543 for chunktype in sorted(chunktypecounts):
541 ui.write(fmtchunktype(chunktype))
544 ui.write(fmtchunktype(chunktype))
542 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
545 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
543
546
544 ui.write(b'\n')
547 ui.write(b'\n')
545 b_total = b"%d" % full_text_total_size
548 b_total = b"%d" % full_text_total_size
546 p_total = []
549 p_total = []
547 while len(b_total) > 3:
550 while len(b_total) > 3:
548 p_total.append(b_total[-3:])
551 p_total.append(b_total[-3:])
549 b_total = b_total[:-3]
552 b_total = b_total[:-3]
550 p_total.append(b_total)
553 p_total.append(b_total)
551 p_total.reverse()
554 p_total.reverse()
552 b_total = b' '.join(p_total)
555 b_total = b' '.join(p_total)
553
556
554 ui.write(b'\n')
557 ui.write(b'\n')
555 ui.writenoi18n(b'total-stored-content: %s bytes\n' % b_total)
558 ui.writenoi18n(b'total-stored-content: %s bytes\n' % b_total)
556 ui.write(b'\n')
559 ui.write(b'\n')
557 fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
560 fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
558 ui.writenoi18n(b'avg chain length : ' + fmt % avgchainlen)
561 ui.writenoi18n(b'avg chain length : ' + fmt % avgchainlen)
559 ui.writenoi18n(b'max chain length : ' + fmt % maxchainlen)
562 ui.writenoi18n(b'max chain length : ' + fmt % maxchainlen)
560 ui.writenoi18n(b'max chain reach : ' + fmt % maxchainspan)
563 ui.writenoi18n(b'max chain reach : ' + fmt % maxchainspan)
561 ui.writenoi18n(b'compression ratio : ' + fmt % compratio)
564 ui.writenoi18n(b'compression ratio : ' + fmt % compratio)
562
565
563 if format > 0:
566 if format > 0:
564 ui.write(b'\n')
567 ui.write(b'\n')
565 ui.writenoi18n(
568 ui.writenoi18n(
566 b'uncompressed data size (min/max/avg) : %d / %d / %d\n'
569 b'uncompressed data size (min/max/avg) : %d / %d / %d\n'
567 % tuple(datasize)
570 % tuple(datasize)
568 )
571 )
569 ui.writenoi18n(
572 ui.writenoi18n(
570 b'full revision size (min/max/avg) : %d / %d / %d\n'
573 b'full revision size (min/max/avg) : %d / %d / %d\n'
571 % tuple(fullsize)
574 % tuple(fullsize)
572 )
575 )
573 ui.writenoi18n(
576 ui.writenoi18n(
574 b'inter-snapshot size (min/max/avg) : %d / %d / %d\n'
577 b'inter-snapshot size (min/max/avg) : %d / %d / %d\n'
575 % tuple(semisize)
578 % tuple(semisize)
576 )
579 )
577 for depth in sorted(snapsizedepth):
580 for depth in sorted(snapsizedepth):
578 if depth == 0:
581 if depth == 0:
579 continue
582 continue
580 ui.writenoi18n(
583 ui.writenoi18n(
581 b' level-%-3d (min/max/avg) : %d / %d / %d\n'
584 b' level-%-3d (min/max/avg) : %d / %d / %d\n'
582 % ((depth,) + tuple(snapsizedepth[depth]))
585 % ((depth,) + tuple(snapsizedepth[depth]))
583 )
586 )
584 ui.writenoi18n(
587 ui.writenoi18n(
585 b'delta size (min/max/avg) : %d / %d / %d\n'
588 b'delta size (min/max/avg) : %d / %d / %d\n'
586 % tuple(deltasize)
589 % tuple(deltasize)
587 )
590 )
588
591
589 if numdeltas > 0:
592 if numdeltas > 0:
590 ui.write(b'\n')
593 ui.write(b'\n')
591 fmt = pcfmtstr(numdeltas)
594 fmt = pcfmtstr(numdeltas)
592 fmt2 = pcfmtstr(numdeltas, 4)
595 fmt2 = pcfmtstr(numdeltas, 4)
593 ui.writenoi18n(
596 ui.writenoi18n(
594 b'deltas against prev : ' + fmt % pcfmt(numprev, numdeltas)
597 b'deltas against prev : ' + fmt % pcfmt(numprev, numdeltas)
595 )
598 )
596 if numprev > 0:
599 if numprev > 0:
597 ui.writenoi18n(
600 ui.writenoi18n(
598 b' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev)
601 b' where prev = p1 : ' + fmt2 % pcfmt(nump1prev, numprev)
599 )
602 )
600 ui.writenoi18n(
603 ui.writenoi18n(
601 b' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev)
604 b' where prev = p2 : ' + fmt2 % pcfmt(nump2prev, numprev)
602 )
605 )
603 ui.writenoi18n(
606 ui.writenoi18n(
604 b' other-ancestor : ' + fmt2 % pcfmt(numoprev, numprev)
607 b' other-ancestor : ' + fmt2 % pcfmt(numoprev, numprev)
605 )
608 )
606 ui.writenoi18n(
609 ui.writenoi18n(
607 b' unrelated : ' + fmt2 % pcfmt(numoprev, numprev)
610 b' unrelated : ' + fmt2 % pcfmt(numoprev, numprev)
608 )
611 )
609 if gdelta:
612 if gdelta:
610 ui.writenoi18n(
613 ui.writenoi18n(
611 b'deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas)
614 b'deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas)
612 )
615 )
613 ui.writenoi18n(
616 ui.writenoi18n(
614 b'deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas)
617 b'deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas)
615 )
618 )
616 ui.writenoi18n(
619 ui.writenoi18n(
617 b'deltas against ancs : '
620 b'deltas against ancs : '
618 + fmt % pcfmt(num_other_ancestors, numdeltas)
621 + fmt % pcfmt(num_other_ancestors, numdeltas)
619 )
622 )
620 ui.writenoi18n(
623 ui.writenoi18n(
621 b'deltas against other : '
624 b'deltas against other : '
622 + fmt % pcfmt(numother_nad, numdeltas)
625 + fmt % pcfmt(numother_nad, numdeltas)
623 )
626 )
624
627
625
628
626 def debug_delta_find(ui, revlog, rev, base_rev=nodemod.nullrev):
629 def debug_delta_find(ui, revlog, rev, base_rev=nodemod.nullrev):
627 """display the search process for a delta"""
630 """display the search process for a delta"""
628 deltacomputer = deltautil.deltacomputer(
631 deltacomputer = deltautil.deltacomputer(
629 revlog,
632 revlog,
630 write_debug=ui.write,
633 write_debug=ui.write,
631 debug_search=not ui.quiet,
634 debug_search=not ui.quiet,
632 )
635 )
633
636
634 node = revlog.node(rev)
637 node = revlog.node(rev)
635 p1r, p2r = revlog.parentrevs(rev)
638 p1r, p2r = revlog.parentrevs(rev)
636 p1 = revlog.node(p1r)
639 p1 = revlog.node(p1r)
637 p2 = revlog.node(p2r)
640 p2 = revlog.node(p2r)
638 full_text = revlog.revision(rev)
641 full_text = revlog.revision(rev)
639 btext = [full_text]
642 btext = [full_text]
640 textlen = len(btext[0])
643 textlen = len(btext[0])
641 cachedelta = None
644 cachedelta = None
642 flags = revlog.flags(rev)
645 flags = revlog.flags(rev)
643
646
644 if base_rev != nodemod.nullrev:
647 if base_rev != nodemod.nullrev:
645 base_text = revlog.revision(base_rev)
648 base_text = revlog.revision(base_rev)
646 delta = mdiff.textdiff(base_text, full_text)
649 delta = mdiff.textdiff(base_text, full_text)
647
650
648 cachedelta = (base_rev, delta, constants.DELTA_BASE_REUSE_TRY)
651 cachedelta = (base_rev, delta, constants.DELTA_BASE_REUSE_TRY)
649 btext = [None]
652 btext = [None]
650
653
651 revinfo = revlogutils.revisioninfo(
654 revinfo = revlogutils.revisioninfo(
652 node,
655 node,
653 p1,
656 p1,
654 p2,
657 p2,
655 btext,
658 btext,
656 textlen,
659 textlen,
657 cachedelta,
660 cachedelta,
658 flags,
661 flags,
659 )
662 )
660
663
661 fh = revlog._datafp()
664 fh = revlog._datafp()
662 deltacomputer.finddeltainfo(revinfo, fh, target_rev=rev)
665 deltacomputer.finddeltainfo(revinfo, fh, target_rev=rev)
663
666
664
667
665 def debug_revlog_stats(
668 def debug_revlog_stats(
666 repo, fm, changelog: bool, manifest: bool, filelogs: bool
669 repo, fm, changelog: bool, manifest: bool, filelogs: bool
667 ):
670 ):
668 """Format revlog statistics for debugging purposes
671 """Format revlog statistics for debugging purposes
669
672
670 fm: the output formatter.
673 fm: the output formatter.
671 """
674 """
672 fm.plain(b'rev-count data-size inl type target \n')
675 fm.plain(b'rev-count data-size inl type target \n')
673
676
674 revlog_entries = [e for e in repo.store.walk() if e.is_revlog]
677 revlog_entries = [e for e in repo.store.walk() if e.is_revlog]
675 revlog_entries.sort(key=lambda e: (e.revlog_type, e.target_id))
678 revlog_entries.sort(key=lambda e: (e.revlog_type, e.target_id))
676
679
677 for entry in revlog_entries:
680 for entry in revlog_entries:
678 if not changelog and entry.is_changelog:
681 if not changelog and entry.is_changelog:
679 continue
682 continue
680 elif not manifest and entry.is_manifestlog:
683 elif not manifest and entry.is_manifestlog:
681 continue
684 continue
682 elif not filelogs and entry.is_filelog:
685 elif not filelogs and entry.is_filelog:
683 continue
686 continue
684 rlog = entry.get_revlog_instance(repo).get_revlog()
687 rlog = entry.get_revlog_instance(repo).get_revlog()
685 fm.startitem()
688 fm.startitem()
686 nb_rev = len(rlog)
689 nb_rev = len(rlog)
687 inline = rlog._inline
690 inline = rlog._inline
688 data_size = rlog._get_data_offset(nb_rev - 1)
691 data_size = rlog._get_data_offset(nb_rev - 1)
689
692
690 target = rlog.target
693 target = rlog.target
691 revlog_type = b'unknown'
694 revlog_type = b'unknown'
692 revlog_target = b''
695 revlog_target = b''
693 if target[0] == constants.KIND_CHANGELOG:
696 if target[0] == constants.KIND_CHANGELOG:
694 revlog_type = b'changelog'
697 revlog_type = b'changelog'
695 elif target[0] == constants.KIND_MANIFESTLOG:
698 elif target[0] == constants.KIND_MANIFESTLOG:
696 revlog_type = b'manifest'
699 revlog_type = b'manifest'
697 revlog_target = target[1]
700 revlog_target = target[1]
698 elif target[0] == constants.KIND_FILELOG:
701 elif target[0] == constants.KIND_FILELOG:
699 revlog_type = b'file'
702 revlog_type = b'file'
700 revlog_target = target[1]
703 revlog_target = target[1]
701
704
702 fm.write(b'revlog.rev-count', b'%9d', nb_rev)
705 fm.write(b'revlog.rev-count', b'%9d', nb_rev)
703 fm.write(b'revlog.data-size', b'%12d', data_size)
706 fm.write(b'revlog.data-size', b'%12d', data_size)
704
707
705 fm.write(b'revlog.inline', b' %-3s', b'yes' if inline else b'no')
708 fm.write(b'revlog.inline', b' %-3s', b'yes' if inline else b'no')
706 fm.write(b'revlog.type', b' %-9s', revlog_type)
709 fm.write(b'revlog.type', b' %-9s', revlog_type)
707 fm.write(b'revlog.target', b' %s', revlog_target)
710 fm.write(b'revlog.target', b' %s', revlog_target)
708
711
709 fm.plain(b'\n')
712 fm.plain(b'\n')
General Comments 0
You need to be logged in to leave comments. Login now