0Pricing
R Academy · บทเรียน

การวิเคราะห์ประสิทธิภาพโค้ดด้วย Rprof และ profvis

ระบุว่าฟังก์ชันใดใช้เวลามากที่สุดในสคริปต์ของคุณ

การวิเคราะห์ประสิทธิภาพโค้ดด้วย Rprof และ profvis เป็นบทเรียน R Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน R Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน

การทำโปรไฟล์คืออะไร

การจับเวลาบอกว่าโค้ดทำงานนานเท่าใด ส่วนการทำโปรไฟล์บอกว่าเวลาถูกใช้ไปที่ใดภายในโค้ดนั้น เครื่องมือทำโปรไฟล์ของ R จะสุ่มตัวอย่างสแต็กการเรียกใช้เป็นระยะ เพื่อสร้างภาพเชิงสถิติว่าฟังก์ชันใดใช้ทรัพยากรมาก

เครื่องมือหลักมีสองอย่าง ได้แก่ Rprof() ซึ่งมีมาให้ในตัว และแพ็กเกจ profvis แบบโต้ตอบ

การเริ่มและหยุด Rprof()

Rprof('output.prof', interval = 0.01) จะเริ่มทำโปรไฟล์ โดยเขียนตัวอย่างสแต็กการเรียกใช้ลงในไฟล์ทุก 10 มิลลิวินาที ให้เรียกใช้โค้ดที่ช้า จากนั้นเรียก Rprof(NULL) เพื่อหยุดบันทึก

อาร์กิวเมนต์ interval ควบคุมความถี่ในการสุ่มตัวอย่างเป็นวินาที — ค่าที่น้อยลงให้รายละเอียดมากขึ้น แต่ทำให้ไฟล์ผลลัพธ์มีขนาดใหญ่ขึ้น

# Pattern — do not run Rprof inside knitr/Quarto
# Rprof('my_profile.prof', interval = 0.01)
#
# slow_function <- function(n) {
#   x <- numeric(n)
#   for (i in seq_len(n)) x[i] <- sqrt(i)
#   sum(x)
# }
# slow_function(500000)
#
# Rprof(NULL)  # stop profiling

การอ่านผลลัพธ์ด้วย summaryRprof()

summaryRprof('output.prof') แยกวิเคราะห์ไฟล์การทำโปรไฟล์และส่งคืนรายการที่มีกรอบข้อมูลสองชุด:

  • by.self — เวลาที่ใช้ในแต่ละฟังก์ชันเอง (ไม่รวมฟังก์ชันที่ถูกเรียก)
  • by.total — เวลารวม ซึ่งรวมฟังก์ชันทั้งหมดที่ฟังก์ชันนั้นเรียก

เรียงลำดับตาม self.pct เพื่อค้นหาจุดที่ใช้เวลามาก

# After Rprof() run:
# prof <- summaryRprof('my_profile.prof')
# head(prof$by.self)
#
# Example output columns:
#            self.time self.pct total.time total.pct
# slow_fn        1.22     61.0       1.98      99.0
# sqrt           0.76     38.0       0.76      38.0
# sum            0.02      1.0       0.02       1.0

เวลาเฉพาะฟังก์ชันเทียบกับเวลารวม

การเข้าใจเวลาเฉพาะฟังก์ชันเทียบกับเวลารวมเป็นสิ่งสำคัญในการทำโปรไฟล์:

  • เวลาเฉพาะฟังก์ชัน — เวลาที่ฟังก์ชันใช้ทำงานในบรรทัดของตนเอง (ไม่รวมเวลาที่รอฟังก์ชันที่ถูกเรียก)
  • เวลารวม — เวลาเฉพาะฟังก์ชันบวกกับเวลาทั้งหมดที่ใช้ในฟังก์ชันซึ่งฟังก์ชันนั้นเรียก

ฟังก์ชันที่มีเวลารวมสูงแต่เวลาเฉพาะฟังก์ชันต่ำ ทำงานช้าเพราะสิ่งที่ฟังก์ชันนั้นเรียกใช้ ไม่ใช่ตรรกะของตัวเอง ให้ปรับปรุงฟังก์ชันที่ถูกเรียก ไม่ใช่ฟังก์ชันผู้เรียก

# Conceptual example:
# wrapper() -> process_data() -> slow_sort()
#
# total.pct: wrapper=100, process_data=90, slow_sort=85
# self.pct:  wrapper=5,   process_data=5,  slow_sort=85
#
# => slow_sort is the real bottleneck to fix.
cat('High total + low self => the culprit is a callee function
')

แนะนำ profvis

profvis ทำงานครอบ Rprof() และแสดงกราฟเปลวไฟ HTML แบบโต้ตอบใน RStudio หรือเบราว์เซอร์ อ่านได้ง่ายกว่าผลลัพธ์ดิบจาก summaryRprof() อย่างมาก

ติดตั้งเพียงครั้งเดียวด้วย install.packages('profvis') จากนั้นครอบโค้ดด้วย profvis({...})

# library(profvis)
#
# profvis({
#   n <- 200000
#   x <- numeric(n)
#   for (i in seq_len(n)) x[i] <- log(i)
#   total <- sum(x)
#   sorted <- sort(x)
# })

การอ่านกราฟเปลวไฟของ profvis

ผลลัพธ์จาก profvis มีสองแผง:

  • กราฟเปลวไฟ — แถบแนวนอนที่ความกว้าง = เวลา แถบที่ซ้อนกัน = ระดับความลึกของสแต็กการเรียกใช้
  • ตารางข้อมูล — มุมมองที่จัดเรียงได้ของเวลาเฉพาะฟังก์ชันและเวลารวมของแต่ละฟังก์ชันและบรรทัดต้นฉบับ

แถบกว้างบริเวณด้านล่างของกราฟเปลวไฟคือฟังก์ชันผู้เรียกที่ใช้ทรัพยากรมากที่สุด สแต็กที่สูงบ่งบอกสายการเรียกใช้ที่ลึก

# Reading the flame graph:
# - Each horizontal bar = one function on the call stack
# - Width proportional to time spent
# - Bottom = outermost caller, top = deepest callee
# - Click a bar to zoom in
# - 'Memory' tab shows allocation by line
cat('profvis shows self time per source line — invaluable for tight loops
')

การระบุจุดที่ใช้เวลามาก

หลังดูผลลัพธ์จาก profvis แล้ว ให้ระบุจุดที่ใช้เวลามากโดยมองหาฟังก์ชันที่มีแถบกว้างในกราฟเปลวไฟและมีเวลาเฉพาะฟังก์ชันสูง สาเหตุที่พบบ่อยใน R ได้แก่:

  • ลูปที่ไม่ใช้เวกเตอร์และทำงานทีละองค์ประกอบ
  • การเรียก rbind() หรือ c() ซ้ำ ๆ จนทำให้ออบเจ็กต์มีขนาดใหญ่ขึ้นภายในลูป
  • การประมวลผลนิพจน์ประจำหรือข้อความซ้ำ ๆ ในลูปที่ทำงานถี่
# Before fix — growing vector in loop (common hot spot)
# profvis reveals repeated reallocations:
# result <- c()
# for (i in 1:50000) result <- c(result, i^2)
#
# After fix — pre-allocated:
# result <- numeric(50000)
# for (i in 1:50000) result[i] <- i^2
cat('Pre-allocation eliminates the most common loop hot spot
')

การทำโปรไฟล์การจัดสรรหน่วยความจำ

Rprof ยังติดตามการจัดสรรหน่วยความจำได้ด้วย memory.profiling = TRUE โดย profvis จะแสดงแผงหน่วยความจำควบคู่กับการจับเวลา ช่วยให้คุณมองเห็นฟังก์ชันที่จัดสรรออบเจ็กต์ชั่วคราวขนาดใหญ่ ซึ่งเป็นสาเหตุสำคัญของการหยุดชะงักระหว่างการเก็บคืนหน่วยความจำ

# Memory profiling with Rprof:
# Rprof('mem.prof', interval = 0.01, memory.profiling = TRUE)
# ... slow code ...
# Rprof(NULL)
# prof <- summaryRprof('mem.prof', memory = 'both')
# head(prof$by.self)
#
# profvis also shows mem delta per line automatically
cat('Memory profiling pinpoints allocation hot spots causing GC pauses
')

การทำโปรไฟล์กระบวนการประมวลผลข้อมูลจริง

ใช้การทำโปรไฟล์กับกระบวนการประมวลผลข้อมูลอย่างเป็นระบบ: ครอบกระบวนการทั้งหมดด้วย profvis({}) ระบุขั้นตอนที่ช้าที่สุด ปรับปรุงขั้นตอนนั้น แล้วทำโปรไฟล์ซ้ำเพื่อยืนยันว่าดีขึ้น อย่าปรับปรุงโดยปราศจากข้อมูล

# Workflow:
# 1. profvis({ full_pipeline() })   => identify Stage 3 is 80% of time
# 2. Rewrite Stage 3 (vectorize / use data.table)
# 3. profvis({ full_pipeline() })   => confirm Stage 3 now < 10%
# 4. system.time({ full_pipeline() }) => confirm overall speedup
cat('Profile -> identify -> fix -> re-profile is the correct cycle
')

ข้อจำกัดของการสุ่มตัวอย่างด้วย Rprof

Rprof ใช้การสุ่มตัวอย่างเชิงสถิติ ดังนั้นฟังก์ชันที่ทำงานเร็วมาก (เร็วกว่าช่วงเวลาสุ่มตัวอย่าง) อาจไม่ปรากฏ สำหรับการวัดประสิทธิภาพระดับย่อยของนิพจน์ขนาดเล็ก ให้ใช้แพ็กเกจ microbenchmark แทน

นอกจากนี้ Rprof ยังไม่ทำโปรไฟล์โค้ด C/C++ ที่อยู่ลึกกว่าจุดเชื่อมต่อกับ R — จะมองเห็นเฉพาะสแต็กการเรียกใช้ระดับ R เท่านั้น

# Rprof interval = 0.01s => functions faster than 10ms may not appear
# For sub-millisecond work use microbenchmark:
#   microbenchmark(expr1, expr2, times = 1000L)
#
# For C-level profiling use external tools:
#   - Instruments (macOS)
#   - perf (Linux)
cat('Rprof is for R-level profiling; use microbenchmark for micro-timing
')

แนวทางปฏิบัติที่ดีที่สุดสำหรับการทำโปรไฟล์ R

ปฏิบัติตามแนวทางเหล่านี้เพื่อให้ได้ผลการทำโปรไฟล์ที่น่าเชื่อถือ:

  • ทำโปรไฟล์ด้วยขนาดข้อมูลที่ใกล้เคียงการใช้งานจริง — ข้อมูลขนาดเล็กจะบดบังคอขวดที่แท้จริง
  • เรียกใช้รอบเตรียมความพร้อมก่อนทำโปรไฟล์ เพื่อไม่นับต้นทุนการตั้งค่าที่เกิดขึ้นครั้งเดียว
  • ทำโปรไฟล์ในเซสชัน R ที่สะอาด เพื่อหลีกเลี่ยงการรบกวนจากแพ็กเกจที่โหลดไว้
  • ใช้ profvis เพื่อสำรวจ และใช้ summaryRprof สำหรับรายงาน CI/รายงานอัตโนมัติ
# Clean session profiling checklist:
# 1. Restart R (Ctrl+Shift+F10 in RStudio)
# 2. Load only required packages
# 3. Run once to warm up
# 4. profvis({ ... })  on second run
# 5. Compare before/after with system.time()
cat('Always profile with realistic data in a clean R session
')

ตรวจสอบด่วน: เวลาเฉพาะฟังก์ชันเทียบกับเวลารวมของ Rprof

ฟังก์ชันหนึ่งแสดงค่า total.pct = 95% แต่แสดงค่า self.pct = 3% ในผลลัพธ์ของ summaryRprof() สิ่งนี้บอกอะไรคุณ

สรุปเครื่องมือทำโปรไฟล์

R มีชุดเครื่องมือทำโปรไฟล์สองระดับ:

  • Rprof('file.prof', interval=0.01) + Rprof(NULL) + summaryRprof() — มีมาให้ในตัว ใช้ในสคริปต์ได้ และเหมาะกับ CI
  • profvis({...}) — กราฟเปลวไฟแบบโต้ตอบ พร้อมคำอธิบายประกอบบรรทัดต้นฉบับและการติดตามหน่วยความจำ

กระบวนการที่ถูกต้องคือ วัดผลก่อนเสมอ ระบุจุดที่ใช้เวลามากที่สุด ปรับปรุงเฉพาะจุดนั้น แล้ววัดซ้ำเพื่อยืนยันผลลัพธ์ที่ดีขึ้น

คำถามที่พบบ่อย

บทเรียน “การวิเคราะห์ประสิทธิภาพโค้ดด้วย Rprof และ profvis” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การวิเคราะห์ประสิทธิภาพโค้ดด้วย Rprof และ profvis” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส R Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส R Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การวิเคราะห์ประสิทธิภาพโค้ดด้วย Rprof และ profvis”

ระบุว่าฟังก์ชันใดใช้เวลามากที่สุดในสคริปต์ของคุณ คุณปฏิบัติ R Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน R Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน R Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน

บทเรียน “การวิเคราะห์ประสิทธิภาพโค้ดด้วย Rprof และ profvis” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน R Academy นี้ได้ไหม

ได้ บทเรียน R Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. system.time() และ proc.time()
  2. การวิเคราะห์ประสิทธิภาพโค้ดด้วย Rprof และ profvis
  3. เวกเตอร์ไรซ์เพื่อความเร็ว
  4. การเปรียบเทียบประสิทธิภาพด้วย microbenchmark
← กลับไปที่ R Academy