Skip to content

Commit 2b81254

Browse files
committed
gdb: speed up lj-gctop command
1 parent b587858 commit 2b81254

File tree

1 file changed

+72
-14
lines changed

1 file changed

+72
-14
lines changed

src/luajit-gdb.py

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
# GDB extension for LuaJIT post-mortem analysis.
22
# To use, just put 'source <path-to-repo>/src/luajit-gdb.py' in gdb.
33

4+
import bisect
45
import re
56
import gdb
67
import sys
8+
import time
9+
from contextlib import contextmanager
10+
from datetime import timedelta
711

812
# make script compatible with the ancient Python {{{
913

@@ -1115,21 +1119,75 @@ def mem_estimate_wp(gcobj):
11151119
return mem_estimate[int(gcobj['gch']['gct'] - ~LJ_TSTR)](gcobj)
11161120

11171121

1122+
class SortedList:
1123+
def __init__(self, key_func, num_values):
1124+
self.__key_func = key_func
1125+
self.__num_values = num_values
1126+
self.__keys = []
1127+
self.__values = []
1128+
1129+
@property
1130+
def values(self):
1131+
return self.__values
1132+
1133+
def insert(self, gco):
1134+
key = self.__key_func(gco)
1135+
i = bisect.bisect(self.__keys, key)
1136+
if len(self.__values) < self.__num_values:
1137+
self.__keys.insert(i, key)
1138+
self.__values.insert(i, gco)
1139+
elif i > 0:
1140+
self.__keys.insert(i, key)
1141+
self.__values.insert(i, gco)
1142+
del self.__keys[0]
1143+
del self.__values[0]
1144+
1145+
1146+
@contextmanager
1147+
def timer():
1148+
start_time = time.time()
1149+
try:
1150+
yield
1151+
finally:
1152+
elapsed_time = int(time.time() - start_time)
1153+
gdb.write(" - took {} seconds / {}\n".format(
1154+
elapsed_time,
1155+
str(timedelta(seconds=elapsed_time)),
1156+
))
1157+
1158+
1159+
def gcobjects(gc):
1160+
obj = gcref(gc['root'])
1161+
while obj:
1162+
yield obj
1163+
obj = gcref(obj['gch']['nextgc'])
1164+
1165+
11181166
def gctop(amount):
1119-
result = []
1120-
g = G(L(None))
1121-
root = g['gc']['root']
1122-
while gcref(root):
1123-
gcobj = gcref(root)
1124-
if len(result) < amount:
1125-
result.insert(len(result), gcobj)
1126-
else:
1127-
objsize = mem_estimate_wp(gcobj)
1128-
if objsize > mem_estimate_wp(result[len(result) - 1]):
1129-
result[len(result) - 1] = gcobj
1130-
result.sort(key=mem_estimate_wp, reverse=True)
1131-
root = gcref(root)['gch']['nextgc']
1132-
return result
1167+
gc = G(L(None))['gc']
1168+
1169+
with timer():
1170+
num_gcobjs = 0
1171+
for gcobj in gcobjects(gc):
1172+
if not num_gcobjs % 100000:
1173+
gdb.write("\rCalculating number of objects... {}".format(num_gcobjs))
1174+
gdb.flush()
1175+
num_gcobjs += 1
1176+
gdb.write("\rCalculating number of objects... {}".format(num_gcobjs))
1177+
1178+
result = SortedList(mem_estimate_wp, amount)
1179+
1180+
with timer():
1181+
i = 0
1182+
for gcobj in gcobjects(gc):
1183+
if not i % 10000:
1184+
gdb.write("\rCollecting statistic... {:5.2f}%".format(100.0 * i / num_gcobjs))
1185+
gdb.flush()
1186+
result.insert(gcobj)
1187+
i += 1
1188+
gdb.write("\rCollecting statistic... 100%")
1189+
1190+
return result.values
11331191

11341192

11351193
def dump_objects(objlist):

0 commit comments

Comments
 (0)