Bun.nanoseconds: จับเวลาช่วงสั้นด้วยนาฬิกา monotonic
ถ้าจะตอบว่าโค้ดหนึ่งช่วงใช้เวลานานเท่าไร เราต้องการนาฬิกาที่เดินไปข้างหน้าเสมอ ไม่ใช่เวลาปฏิทินที่อาจถูก NTP หรือผู้ใช้ปรับย้อนหลัง Bun.nanoseconds คืนค่าจาก monotonic clock สำหรับคำนวณ ช่วงเวลา ความละเอียดระดับนาโนวินาทีครับ
WHY: elapsed time ไม่ใช่ timestamp
Date.now เหมือนมองนาฬิกาแขวนผนัง เหมาะกับบอกว่าเหตุการณ์เกิดเมื่อไร แต่คนดูแลระบบอาจหมุนเข็มให้ตรงกับเวลาจริง ส่วน monotonic clock เหมือนนาฬิกาจับเวลาวิ่ง: สนใจระยะจากจุดเริ่มถึงจุดจบและไม่ควรถอยหลัง ค่า Bun.nanoseconds จึงไม่มีความหมายเป็นวันเวลาและห้ามนำไป serialize เป็น timestamp
const start = Bun.nanoseconds();
let checksum = 0;
for (let i = 0; i < 100_000; i++) {
checksum = (checksum + i) % 97;
}
const elapsedNs = Bun.nanoseconds() - start;
if (!Number.isFinite(elapsedNs) || elapsedNs < 0) {
throw new Error("monotonic elapsed time must be non-negative");
}
if (checksum !== 28) {
throw new Error("workload result changed");
}
console.log({ elapsedNs, elapsedMs: elapsedNs / 1_000_000 });
ค่าเป็น number จึงสะดวกสำหรับการลบและแปลงหน่วย แต่ไม่ควรตีความทุกหลักเป็นความแม่นยำจริง ฮาร์ดแวร์และระบบปฏิบัติการอาจมี resolution หยาบกว่า และ JIT, GC, scheduler, thermal throttling รวมถึงงานอื่นในเครื่องทำให้ผลแกว่ง การวัดครั้งเดียวจึงเป็น “ภาพถ่าย” ไม่ใช่ benchmark
ใช้ให้ผลน่าเชื่อขึ้น
อุ่นเครื่องโค้ดก่อน เก็บหลายรอบ รายงาน median/p95 และแยก setup ออกจากช่วงที่ต้องการวัด หากเทียบสอง implementation ให้สลับลำดับเพื่อไม่ให้ตัวแรกหรือหลังได้เปรียบจาก cache ที่อุ่นแล้ว งาน production ควรวัด metric ระดับ request ด้วยระบบ observability มากกว่าพิมพ์ค่า microbenchmark ทุกครั้ง
ถ้าต้องการ API มาตรฐานข้าม runtime ใช้ performance.now ซึ่งให้หน่วยมิลลิวินาทีแบบ monotonic เช่นกัน ส่วน Bun.nanoseconds เหมาะเมื่ออยู่บน Bun แน่นอนและอยากลดการแปลงหน่วยในช่วงสั้น
Recap
- ลบค่าก่อน-หลังเพื่อหา elapsed time เท่านั้น
- แปลงนาโนวินาทีเป็นมิลลิวินาทีด้วยการหารหนึ่งล้าน
- อย่าใช้แทน timestamp หรือเวลาปฏิทิน
- benchmark หลายรอบและรายงานการกระจาย