Skip to content

Commit 06f432e

Browse files
author
MSCodeBase Agent
committed
perf: Variant A — embedding 14x faster + bulk write + idle timeout
1 parent 18335b9 commit 06f432e

9 files changed

Lines changed: 502 additions & 77 deletions

File tree

‎scripts/bench_quick.py‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import httpx, time, sys, math
2+
3+
out = []
4+
try:
5+
for bs in [1, 2, 4, 8]:
6+
texts = ["code %d" % i for i in range(bs)]
7+
t0 = time.time()
8+
r = httpx.post("http://127.0.0.1:8080/v1/embeddings", json={"input": texts}, timeout=30)
9+
t1 = time.time()
10+
out.append("batch=%d status=%d time=%.3fs ch/s=%.0f" % (bs, r.status_code, t1 - t0, bs / (t1 - t0)))
11+
time.sleep(0.2)
12+
13+
ok = 0
14+
t0 = time.time()
15+
for i in range(20):
16+
r = httpx.post("http://127.0.0.1:8080/v1/embeddings", json={"input": ["x"] * 4}, timeout=30)
17+
if r.status_code == 200:
18+
ok += 1
19+
t1 = time.time()
20+
out.append("burst20_nosleep: %d/20 ok %.1fs %.0fch/s" % (ok, t1 - t0, 80 / (t1 - t0)))
21+
22+
ok2 = 0
23+
t0 = time.time()
24+
for i in range(20):
25+
r = httpx.post("http://127.0.0.1:8080/v1/embeddings", json={"input": ["x"] * 4}, timeout=30)
26+
if r.status_code == 200:
27+
ok2 += 1
28+
time.sleep(0.3)
29+
t1 = time.time()
30+
out.append("burst20_sleep03: %d/20 ok %.1fs %.0fch/s" % (ok2, t1 - t0, 80 / (t1 - t0)))
31+
32+
r = httpx.post("http://127.0.0.1:8080/v1/embeddings", json={"input": ["test code"] * 8}, timeout=30)
33+
vecs = [d["embedding"] for d in r.json()["data"]]
34+
zeros = sum(1 for v in vecs if max(abs(x) for x in v) < 1e-10)
35+
norms = [math.sqrt(sum(x * x for x in v)) for v in vecs]
36+
out.append("zero_check: %d/%d zeros" % (zeros, len(vecs)))
37+
out.append("norms: %s" % " ".join("%.3f" % n for n in norms))
38+
39+
except Exception as e:
40+
out.append("ERROR: %s" % str(e))
41+
42+
with open("bench_out.txt", "w") as f:
43+
f.write("\n".join(out))
44+
print("DONE")

‎scripts/bench_simple.py‎

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import httpx, time
2+
results = []
3+
for bs in [1, 2, 4, 8]:
4+
texts = ["code snippet %d" % i for i in range(bs)]
5+
times = []
6+
for _ in range(3):
7+
t0 = time.time()
8+
r = httpx.post("http://127.0.0.1:8080/v1/embeddings", json={"input": texts}, timeout=30)
9+
elapsed = time.time() - t0
10+
if r.status_code == 200:
11+
times.append(elapsed)
12+
time.sleep(0.15)
13+
if times:
14+
avg = sum(times)/len(times)
15+
results.append("batch=%d avg=%.3fs ch/s=%.0f" % (bs, avg, bs/avg))
16+
17+
t0 = time.time()
18+
ok = 0
19+
for i in range(30):
20+
r = httpx.post("http://127.0.0.1:8080/v1/embeddings", json={"input": ["x"]*4}, timeout=30)
21+
if r.status_code == 200:
22+
ok += 1
23+
burst1 = time.time() - t0
24+
results.append("burst30_nosleep: %d/30 ok %.1fs %.0fch/s" % (ok, burst1, 120/burst1))
25+
26+
t0 = time.time()
27+
ok2 = 0
28+
for i in range(30):
29+
r = httpx.post("http://127.0.0.1:8080/v1/embeddings", json={"input": ["x"]*4}, timeout=30)
30+
if r.status_code == 200:
31+
ok2 += 1
32+
time.sleep(0.3)
33+
burst2 = time.time() - t0
34+
results.append("burst30_sleep03: %d/30 ok %.1fs %.0fch/s" % (ok2, burst2, 120/burst2))
35+
36+
r = httpx.post("http://127.0.0.1:8080/v1/embeddings", json={"input": ["test code"]*8}, timeout=30)
37+
vecs = [d["embedding"] for d in r.json()["data"]]
38+
import math
39+
zeros = sum(1 for v in vecs if max(abs(x) for x in v) < 1e-10)
40+
norms = [math.sqrt(sum(x*x for x in v)) for v in vecs]
41+
results.append("zero_check: %d/%d zeros, norms=[%s]" % (zeros, len(vecs), ",".join("%.3f" % n for n in norms)))
42+
43+
with open("embed_bench_result.txt","w") as f:
44+
f.write("\n".join(results))
45+
print("OK")
46+
for r in results:
47+
print(r)

‎scripts/check_zero_vectors.py‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import time, math, sys
2+
if sys.stdout.encoding != 'utf-8':
3+
sys.stdout.reconfigure(encoding='utf-8')
4+
5+
for i in range(24):
6+
time.sleep(5)
7+
try:
8+
import lancedb
9+
db = lancedb.connect('.codebase_indices/lancedb_v2/index_mscodebase_bfe9644b.db')
10+
tbl = db.open_table('codebase_chunks')
11+
n = tbl.count_rows()
12+
if n > 0:
13+
print('rows=%d' % n)
14+
if n >= 4000:
15+
df = tbl.to_pandas()
16+
zeros = 0
17+
norms = []
18+
for j in range(n):
19+
v = df.iloc[j]['vector']
20+
if max(abs(x) for x in v) < 1e-10:
21+
zeros += 1
22+
norms.append(math.sqrt(sum(x*x for x in v)))
23+
print('ZERO_CHECK: %d/%d zeros' % (zeros, n))
24+
print('min_norm=%.4f max_norm=%.4f avg_norm=%.4f' % (min(norms), max(norms), sum(norms)/len(norms)))
25+
v0 = df.iloc[0]['vector']
26+
print('row0 min=%.4f max=%.4f' % (min(v0), max(v0)))
27+
break
28+
except Exception as e:
29+
pass
30+
print('CHECK_DONE')

‎scripts/monitor.py‎

Lines changed: 86 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@
6767
monitor_start = time.time()
6868
last_log_offset = 0 # позиция в файле для инкрементального чтения
6969

70+
# Run ID — отличает текущий запуск индексации от предыдущих
71+
current_run_id = None # устанавливается при "Auto-index: starting"
72+
7073

7174
def read_log_incremental():
7275
"""Читает только новые строки из лога (быстро, без перечитывания всего файла)."""
@@ -85,6 +88,28 @@ def read_log_incremental():
8588
return new_lines
8689

8790

91+
def reset_run_state():
92+
"""Сбрасывает ВСЁ состояние при новом запуске индексации."""
93+
global total_chunks, done_chunks, phase, phase_start_time
94+
global db_files_written, db_chunks_written, ivf_started
95+
global recent_ema, ema_initialized, not_found_count
96+
global last_done, last_time, lock_status
97+
total_chunks = 0
98+
done_chunks = 0
99+
phase = PHASE_LOADING
100+
phase_start_time = time.time()
101+
db_files_written = 0
102+
db_chunks_written = 0
103+
ivf_started = False
104+
recent_ema = 0.0
105+
ema_initialized = False
106+
not_found_count = 0
107+
last_done = 0
108+
last_time = time.time()
109+
lock_status = '🔒 Ожидание...'
110+
phase_metrics.clear()
111+
112+
88113
def read_log_tail(n=50):
89114
"""Читает последние N строк лога (для начальной загрузки)."""
90115
if not LOG_FILE.exists():
@@ -206,6 +231,8 @@ def parse_embed_complete(line):
206231
def update_ema(new_speed):
207232
"""Обновляет EMA скорость. Чем больше α, тем быстрее реагирует."""
208233
global recent_ema, ema_initialized
234+
if new_speed <= 0:
235+
return # не портим EMA нулевыми/отрицательными
209236
if not ema_initialized:
210237
recent_ema = new_speed
211238
ema_initialized = True
@@ -252,7 +279,7 @@ def render():
252279
now = time.time()
253280
total_elapsed = now - monitor_start
254281

255-
print("📊 МОНИТОР ИНДЕКСАЦИИ v2")
282+
print("📊 МОНИТОР ИНДЕКСАЦИИ v3")
256283
print("─" * 60)
257284
print(f" Фаза: {phase}")
258285
print(f" Время: {fmt_time(total_elapsed)}")
@@ -275,7 +302,7 @@ def render():
275302
print()
276303

277304
# Эмбеддинг
278-
if total_chunks > 0 and phase in (PHASE_EMBED, PHASE_WRITING, PHASE_IVF, PHASE_DONE):
305+
if total_chunks > 0 and phase in (PHASE_EMBED, PHASE_WRITING, PHASE_IVF):
279306
pct = done_chunks / total_chunks * 100
280307
print(f" 🧠 Эмбеддинг: {bar(done_chunks, total_chunks)} {pct:.0f}%")
281308
print(f" {done_chunks}/{total_chunks} ({total_chunks - done_chunks} осталось)")
@@ -333,17 +360,42 @@ def render():
333360
# ─── Main loop ────────────────────────────────────────────
334361

335362
os.system('cls' if os.name == 'nt' else 'clear')
336-
print("📊 МОНИТОР ИНДЕКСАЦИИ v2")
363+
print("📊 МОНИТОР ИНДЕКСАЦИИ v3")
337364
print("─" * 60)
338365
print(" Инициализация... чтение лога")
339366
print("─" * 60)
340367

341-
# Начальная загрузка — последние 100 строк
342-
initial_lines = read_log_tail(100)
343-
# Обрабатываем начальные данные
368+
# Начальная загрузка — последние 200 строк
369+
initial_lines = read_log_tail(200)
370+
371+
# Шаг 1: Находим последний Auto-index: starting — всё ДО него = старый запуск
372+
_last_auto_start_idx = -1
373+
for _i, line in enumerate(initial_lines):
374+
if parse_auto_index(line) == 'start':
375+
_last_auto_start_idx = _i
376+
377+
if _last_auto_start_idx >= 0:
378+
initial_lines = initial_lines[_last_auto_start_idx + 1:]
379+
_found_complete = any(parse_indexing_complete(l) or parse_ivf_done(l) for l in initial_lines)
380+
if _found_complete:
381+
# Последний запуск уже завершился — начнём как будто ничего не идёт
382+
phase = PHASE_LOADING
383+
384+
# Шаг 2: Обрабатываем строки текущего запуска
344385
for line in initial_lines:
345-
if parse_found_files(line):
346-
phase_metrics['parse_files'] = parse_found_files(line)
386+
# ★ Сброс при новом auto-index start
387+
ai_init = parse_auto_index(line)
388+
if ai_init == 'start':
389+
reset_run_state()
390+
auto_index_status = '🚀 running'
391+
elif ai_init == 'done':
392+
auto_index_status = '✅ done'
393+
elif ai_init == 'failed':
394+
auto_index_status = '❌ failed'
395+
396+
ff = parse_found_files(line)
397+
if ff:
398+
phase_metrics['parse_files'] = ff
347399

348400
tc = parse_total_chunks(line)
349401
if tc:
@@ -359,25 +411,28 @@ def render():
359411
phase_metrics['embed']['elapsed'] = embed['elapsed']
360412
update_ema(embed['inst'])
361413

362-
if parse_db_write(line):
414+
cw = parse_db_write(line)
415+
if cw:
363416
db_files_written += 1
364-
db_chunks_written += parse_db_write(line)
417+
db_chunks_written += cw
365418

366-
if parse_creating_index(line):
367-
phase_metrics['ivf_chunks'] = parse_creating_index(line)
419+
ic = parse_creating_index(line)
420+
if ic:
421+
phase_metrics['ivf_chunks'] = ic
368422
ivf_started = True
369423

370424
if parse_ivf_done(line):
371425
phase = PHASE_DONE
372426

373427
ec = parse_embed_complete(line)
374428
if ec:
429+
phase_metrics.setdefault('embed', {})
375430
phase_metrics['embed']['final_speed'] = ec['speed']
376431
phase_metrics['embed']['elapsed'] = ec['elapsed']
377432

378-
ic = parse_indexing_complete(line)
379-
if ic:
380-
total_chunks = ic
433+
ic2 = parse_indexing_complete(line)
434+
if ic2:
435+
total_chunks = ic2
381436
phase = PHASE_DONE
382437

383438
# Определяем начальную фазу
@@ -399,6 +454,17 @@ def render():
399454

400455
# Обрабатываем новые строки
401456
for line in new_lines:
457+
# ★ ПЕРВЫМ ДЕЛОМ: ловим Auto-index start → сброс всего
458+
ai = parse_auto_index(line)
459+
if ai == 'start':
460+
reset_run_state()
461+
current_run_id = time.time() # noqa: F841 — глобальная
462+
auto_index_status = '🚀 running'
463+
elif ai == 'done':
464+
auto_index_status = '✅ done'
465+
elif ai == 'failed':
466+
auto_index_status = '❌ failed'
467+
402468
# Парсинг файлов
403469
ff = parse_found_files(line)
404470
if ff:
@@ -423,10 +489,10 @@ def render():
423489
phase_metrics['embed']['last_avg_log'] = embed['avg_log']
424490
phase_metrics['embed']['elapsed'] = embed['elapsed']
425491

426-
# EMA: обновляем только если прошло достаточно времени
492+
# EMA: только при росте done_chunks (защита от reset)
427493
now = time.time()
428494
dt = now - last_time
429-
if dt > 0.5 and done_chunks != last_done:
495+
if dt > 0.5 and done_chunks > last_done:
430496
instant_speed = (done_chunks - last_done) / dt
431497
update_ema(instant_speed)
432498
last_done = done_chunks
@@ -438,6 +504,7 @@ def render():
438504
# Embed complete
439505
ec = parse_embed_complete(line)
440506
if ec:
507+
phase_metrics.setdefault('embed', {})
441508
phase_metrics['embed']['final_speed'] = ec['speed']
442509
phase_metrics['embed']['elapsed'] = ec['elapsed']
443510
if phase == PHASE_EMBED:
@@ -477,22 +544,13 @@ def render():
477544
elif nf == 'self_healed':
478545
phase_metrics['self_healed'] = phase_metrics.get('self_healed', 0) + 1
479546

480-
# Auto-index lifecycle
481-
ai = parse_auto_index(line)
482-
if ai == 'start':
483-
auto_index_status = '🚀 running'
484-
elif ai == 'done':
485-
auto_index_status = '✅ done'
486-
elif ai == 'failed':
487-
auto_index_status = '❌ failed'
488-
489547
# IVF done
490548
if parse_ivf_done(line):
491549
phase = PHASE_DONE
492550

493-
# Indexing complete
551+
# Indexing complete — только если мы в активной фазе
494552
ic2 = parse_indexing_complete(line)
495-
if ic2:
553+
if ic2 and phase != PHASE_LOADING:
496554
total_chunks = ic2
497555
phase = PHASE_DONE
498556

0 commit comments

Comments
 (0)