ครั้งแรกที่ฉันพยายาม track เวลาของ local LLM run หนึ่ง ฉันทำมันหลุดมือไป
เช้าวันเสาร์ฉันเริ่ม Q4 quantization ของ model ขนาด 7B ที่ใช้เวลา 3 ชั่วโมง เริ่มจับเวลาใน Toggl แล้วก็ลุกเดินจากไป กลับมาตอนมื้อเที่ยงเจอ Mac ที่หลับอยู่ งานที่ยังไม่เสร็จ และ timer ของ Toggl ที่จดไว้อย่างร่าเริง 3 ชั่วโมง 14 นาที ลงโปรเจกต์ «ml-experiments»
Data นั้นโกหก งานไม่ได้เกิดขึ้นเลย Mac หลับไปหลังผ่านไป 20 นาที quantization หยุด กราฟการใช้ CPU ของฉันในช่วง 3 ชั่วโมงนั้นเป็นเส้นแบนราบ แต่ Toggl ไม่สน — ฉันบอกมันว่าฉันกำลังทำงาน มันก็เลยนับว่าฉันทำงาน
นั่นคือปัญหาเชิงโครงสร้างของการ track เวลาของงาน local AI/ML สิ่งที่ใช้คอมพิวเตอร์ของคุณอยู่นั้นไม่ใช่คุณ สิ่งที่ time tracker ของคุณวัดคือ สิ่งที่คุณกำลังทำ แต่สิ่งที่คุณอยากรู้จริง ๆ คือ model กำลังคืบหน้าหรือเปล่า สองอย่างนี้เป็นสัญญาณคนละตัวกัน
ถึงตอนนี้ฉันใช้เวลารัน fine-tunes, evaluations และ long-context generations แบบ local บน Apple Silicon มามากพอจน workflow ตกผลึกเป็น pattern ไม่กี่แบบ นี่คือสิ่งที่ฉันเรียนรู้เกี่ยวกับการ track มันให้ถูกต้อง — และสิ่งที่ Timex จับได้ซึ่ง tool อื่นพลาดไป
«model กำลังรัน» จริง ๆ แล้วหน้าตาเป็นยังไงในสายตา Mac
เมื่อ Ollama หรือ LM Studio หรือ MLX หรือ llama.cpp กำลังทำงาน app ที่อยู่ foreground ของ Mac คุณก็ยังเป็นอันที่คุณคลิกล่าสุด ปกติก็คือ terminal ที่คุณ launch งานมา หรือหน้าต่าง chat ของ LM Studio หรือ tab browser ที่ชี้ไปที่ localhost:11434 ตัวงานเองเป็น background process เท่าที่ OS รับรู้ คุณ ยังอยู่ที่ terminal อยู่ ถึงแม้คุณจะลุกเดินจากไปตั้งแต่ชั่วโมงที่แล้ว
ถ้าจากนั้นคุณปิดฝาหรือเดินจากไป จะเกิดสองอย่าง:
- macOS ถือว่าคุณ idle (ไม่มี input เกิน 90 วินาที)
- macOS ถือว่าระบบ อาจจะ หลับได้ ขึ้นอยู่กับการตั้งค่า power และฝาปิดอยู่หรือเปล่า
อย่างแรกทำให้ time tracker ของคุณหยุดนับ (ถูกต้อง — คุณไม่ได้ทำงาน) อย่างที่สองทำให้ model ของคุณหยุดรัน (ไม่ถูก — มันกำลังทำงานอยู่)
วิธีแก้อย่างที่สองคือสิ่งที่ฉันเขียนไว้ใน รัน Ollama ใน clamshell mode ถือ power assertion ไว้ Mac จะตื่นอยู่ model จะ generate ต่อไป Timex รวมเรื่องนี้ไว้ในปุ่ม toggle ของ lid-down mode เพื่อที่คุณจะได้ไม่ต้องจำ flag caffeinate
วิธีแก้อย่างแรกคือหัวข้อของโพสต์นี้
สิ่งที่คุณอยากวัดจริง ๆ สำหรับงาน ML
มีระยะเวลาที่ต่างกันสามแบบที่คุณอาจสนใจสำหรับ LLM/ML run หนึ่ง:
- Wall-clock time — run เริ่มเมื่อไหร่ จบเมื่อไหร่ ใช้เวลาทั้งหมดเท่าไหร่
- Compute time — model ทำงานจริงจังตอนไหน (GPU/CPU > 0) ไม่ใช่นั่งรอคุณหรือค้างอยู่
- เวลาความสนใจของคุณ — ตอนไหนที่คุณนั่งดู/คุมการรันอยู่จริง ๆ
สำหรับงาน quantization คุณสนใจ #1 กับ #2 เป็นหลัก (มันมีประสิทธิภาพไหม Mac ตื่นอยู่ตลอดไหม) สำหรับ eval session แบบ interactive คุณสนใจ #3 เป็นหลัก (experiment นี้กินเวลาคุณไปเท่าไหร่) สำหรับการตัดสินใจว่าจะใช้ model ต่อใน production ไหม คุณสนใจทั้งสามอย่าง
time tracker อเนกประสงค์ส่วนใหญ่เอามันมาปนกันหมด Toggl จะบอกคุณว่าคุณใช้เวลา 3 ชั่วโมงไปกับ «ml-experiments» ถ้าคุณกดเริ่มจับเวลาแล้วเดินจากไป RescueTime จะบอกว่าคุณไม่ได้อยู่หน้าคอม ทั้งคู่ถูกต้องในทางเทคนิคและไร้ประโยชน์เมื่ออยู่เดี่ยว ๆ
สิ่งที่คุณต้องการคือ record ว่า run เริ่มเมื่อไหร่ จบเมื่อไหร่ และคุณทำอะไรอยู่ในช่วงเวลานั้น Timex จับทั้งสามอย่างไว้ใน log เดียว
Timex มองเห็น local LLM run อย่างไร
นี่คือรูปร่างจริงของ data จาก Q4 quantization ที่ฉันรันเมื่อสัปดาห์ที่แล้ว Run ใช้เวลา wall-clock 2 ชั่วโมง 41 นาที ฉันนั่งอยู่หน้า keyboard ของมันไป 22 นาที
-- The 3-hour window of the quantization run
SELECT
ts,
app_name,
window_title,
is_idle
FROM activity_samples
WHERE ts BETWEEN strftime('%s', '2026-05-31 09:14:00')
AND strftime('%s', '2026-05-31 11:55:00')
ORDER BY ts;
รูปร่างคร่าว ๆ ของแถว (sampling ทุก 15 นาทีเพื่อให้อ่านง่าย):
09:14 Ghostty llama.cpp quantize-stats ... 0 (active, just started)
09:29 Ghostty llama.cpp quantize-stats ... 0 (active, watching output)
09:44 Ghostty llama.cpp quantize-stats ... 1 (idle, walked away)
09:59 loginwindow — 1 (locked screen)
10:14 loginwindow — 1 (still locked)
... [no rows from 10:30 to 11:30 — display slept, sampler paused]
11:32 Ghostty llama.cpp quantize-stats ... 0 (returned, woke up Mac)
11:47 Ghostty llama.cpp quantize-stats ... 0 (watching final phases)
11:55 Ghostty llama.cpp quantize-done 0 (job finished)
มีบางอย่างที่ควรสังเกต
window title เป็น string เดิมตลอดเวลา (llama.cpp quantize-stats ...) นั่นสำคัญ — แปลว่าทีหลังฉัน grep ไฟล์ SQLite แล้วหา quantization run ทุกครั้งได้จาก window title terminal เก็บชื่อ foreground process ไว้ในแถบ title นั่นคือเกล็ดขนมปังที่ฉันต้องการ
แถวหายไป ในช่วงที่จอหลับ (10:30 ถึง 11:30) นั่นถูกต้อง sampler ไม่ควรอ้างว่ามี activity ตอนที่ไม่มีอะไรถูกบันทึก ช่องว่างใน strip นั้นซื่อสัตย์ — มันแสดงว่า Mac หลับอยู่ — และช่องว่างนี้ก็คือสิ่งที่ฉันอยากไปสืบทีหลังด้วย (นั่นเป็นความล้มเหลวของ clamshell-mode หรือฉันลืมเปิดมัน?)
แถว lock screen ที่อยู่ตรงกลาง (loginwindow) คือทองคำสำหรับการวินิจฉัย มันบอกฉันว่าจอ lock ตอน 09:59 ซึ่งคือตอนที่ฉันออกจากห้อง ถ้าฉันกังวลว่า run รันอยู่จริงไหมตอนที่ฉันไม่อยู่ การไม่มีแถว crash หรือแถวของ app อื่นก็ทำให้สบายใจ
«คราวนี้ lid-down mode ทำงานไหม?»
นี่คือคำถามที่ฉันถามเกี่ยวกับ ML runs ของตัวเองบ่อยที่สุด Mac ตื่นอยู่ตลอดไหม? หรือ clamshell ล้มเหลวตรงจุดไหนสักจุด?
SQL query ให้คำตอบ:
-- For a known run window, find any gap > 5 minutes (= sleep event)
WITH sample_gaps AS (
SELECT
ts AS t,
ts - LAG(ts) OVER (ORDER BY ts) AS gap_seconds
FROM activity_samples
WHERE ts BETWEEN strftime('%s', '2026-05-31 09:14:00')
AND strftime('%s', '2026-05-31 11:55:00')
)
SELECT datetime(t, 'unixepoch', 'localtime') AS gap_started, gap_seconds
FROM sample_gaps
WHERE gap_seconds > 300
ORDER BY t;
ถ้า lid-down mode ทำงานได้สมบูรณ์ query นี้จะคืนค่ามาศูนย์แถว ถ้า Mac หลับไปตรงจุดใดก็ตาม คุณจะได้แถวหนึ่งต่อหนึ่งช่วงหลับ พร้อมเวลาเริ่มและระยะเวลา
สำหรับ run ข้างบน คำตอบคือ: ช่องว่างหนึ่งช่อง 53 นาที Mac หลับตั้งแต่ 10:30 ถึง 11:23 lid-down mode ไม่ได้เปิดไว้ ฉันลืมกดเปิดมัน quantization หยุดไปหนึ่งชั่วโมง ตื่นขึ้นตอนที่ฉันกลับมาและขยับเมาส์ แล้วก็รันต่อ
Run ทั้งหมดใช้เวลานานกว่าที่ควรจะเป็นไป 1 ชั่วโมง 53 นาที นี่คือคำถามประเภทที่คุณถามไม่ได้เลยถ้าไม่มี tracker ที่บันทึกช่องว่างอย่างซื่อสัตย์
การ annotate runs โดยไม่ต้องออกจาก terminal
กลไก «run นี้ทำไปเพื่ออะไร» ที่ง่ายที่สุดคือ window title ของ terminal terminal ส่วนใหญ่ให้คุณตั้ง title ได้ด้วย ANSI escape:
echo -ne "\033]0;quant-7b-q4 — eval-set-3\007"
ollama run mistral:7b-instruct-q4 < eval-set-3.jsonl > out.jsonl
นั่นจะตั้ง window title เป็น «quant-7b-q4 — eval-set-3» ตลอดช่วงที่ command ทำงาน Timex จับ title นั้นไว้ในทุกแถว sample ทีหลังคุณ grep หา eval-set-3 แล้วดึงช่วงเวลาที่แน่นอนของ experiment นั้นออกมาได้
ทริกนี้ใช้ทั่วไปได้:
# Wrap any long-running ML command with a title tag
run_titled() {
local title="$1"
shift
echo -ne "\033]0;${title}\007"
"$@"
echo -ne "\033]0;${SHELL##*/}\007"
}
run_titled "mlx-finetune-llama3-r1-lr2e5" python finetune.py --lr 2e-5
ตอนนี้ทุกแถว sample ภายในช่วงนั้นจะโผล่มาเป็น mlx-finetune-llama3-r1-lr2e5 ใน window title และคุณดึงเวลา start/end ที่แน่นอนกับ pattern ของ idle ออกมาจาก SQLite ได้หลังผ่านไปหลายสัปดาห์ มันคือรูปแบบการ track experiment ที่ถูกที่สุดเท่าที่จะนึกออก และมันอยู่รอดได้โดยไม่ต้องพึ่ง cloud service ใด ๆ
หนึ่งสัปดาห์ ML จริง ๆ
นี่คือหน้าตาของงานที่ตั้ง title mlx-* และ llama-* เมื่อสัปดาห์ที่แล้วใน data:
SELECT
window_title,
date(MIN(ts), 'unixepoch', 'localtime') AS started,
ROUND((MAX(ts) - MIN(ts)) / 60.0, 1) AS wall_minutes,
ROUND(SUM(CASE WHEN is_idle = 0 THEN 1 ELSE 0 END) / 60.0, 1) AS active_minutes
FROM activity_samples
WHERE window_title LIKE 'mlx-%' OR window_title LIKE 'llama-%'
GROUP BY window_title
ORDER BY MIN(ts);
Output:
mlx-finetune-llama3-r1-lr2e5 2026-05-26 189.2 wall 34.1 active
llama-cpp-quant-7b-q4-eval3 2026-05-31 161.8 wall 22.4 active
llama-cpp-quant-7b-q8-eval3 2026-06-01 178.5 wall 18.9 active
mlx-eval-mtbench-r1-vs-base 2026-06-02 87.0 wall 71.2 active
Eval (แถวสุดท้าย) เป็น wall-clock 87 นาทีและ active 71 นาที — นั่นเป็น session การให้คะแนนแบบ interactive ที่ฉันนั่งดู output แบบ real time งาน quantization สองงานเป็นความสนใจของฉัน 18–22 นาทีต่อ wall-clock 2.5–3 ชั่วโมง — เป็น run ยาว ๆ ที่ไม่มีคนเฝ้า
อัตราส่วนนั้นสำคัญ คอลัมน์ active-เทียบ-wall บอกฉันว่า experiment ไหนกินเวลาฉันและอันไหนกินค่าไฟฉัน การตัดสินใจที่ตามมาก็ต่างกัน
คุณยอมเสียอะไรไปเทียบกับ ML experiment tracker «ตัวจริง»
นี่คือสิ่งที่ Timex เป็นและไม่เป็นสำหรับ workflow ของ ML
experiment tracker เฉพาะทาง — Weights & Biases, MLflow, Aim — track ตัว model Loss curves, hyperparameters, metrics, artifacts ไม่มีอะไรพวกนี้อยู่ใน Timex ถ้าคุณต้องการสิ่งนั้น ให้รัน W&B ควบคู่ไป ทั้งสองเสริมกัน
สิ่งที่ Timex track คือ ด้านมนุษย์ของการรัน คุณเริ่มมันเมื่อไหร่ คุณลุกเดินจากไปเมื่อไหร่ มันจบเมื่อไหร่ ระหว่างนั้นคุณทำอะไรอยู่ Mac ตื่นอยู่ไหม คุณแอบไปเช็ก Twitter ตอนมันรันอยู่ไหม ไม่มีอะไรพวกนี้อยู่ใน W&B
ถ้าคุณทำ ML จริงจังบน Mac และไม่ได้ log data ด้าน «มนุษย์» ใด ๆ เลย — คนส่วนใหญ่ก็ไม่ได้ทำ — Timex คือวิธีที่ถูกที่สุดที่จะเริ่ม Data อยู่ในไฟล์ SQLite ที่คุณเข้าใจอยู่แล้ว Query สั้น ๆ Graph ก็คือ strip ใน Today view
และในด้านปฏิบัติ: lid-down mode คือ feature ที่ทำให้ run ข้ามคืนบน laptop เป็นไปได้จริง ถ้าคุณเคยตื่นมาเจอ training ที่เสร็จ 30% ทั้งที่ควรจะเสร็จ 100% คุณก็รู้อยู่แล้วว่าทำไม
รันงานข้ามคืนงานถัดไปของคุณ โดยเปิด clamshell mode ของ Timex ไว้ Log SQLite จะบอกคุณตอนเช้าว่ามันได้ผลไหม