การเพิ่มประสิทธิภาพแบบแนะนำโปรไฟล์

การเพิ่มประสิทธิภาพที่แนะนําโดยโปรไฟล์ (PGO) เป็นเทคนิคการเพิ่มประสิทธิภาพคอมไพเลอร์ที่รู้จักกันดี ใน PGO คอมไพเลอร์จะใช้โปรไฟล์รันไทม์จากการเรียกใช้โปรแกรมเพื่อเลือกการฝังและเลย์เอาต์โค้ดที่เหมาะสมที่สุด ซึ่งส่งผลให้ประสิทธิภาพดีขึ้นและขนาดโค้ดลดลง

คุณติดตั้งใช้งาน PGO ในแอปพลิเคชันหรือไลบรารีได้โดยทำตามขั้นตอนต่อไปนี้ 1. ระบุภาระงานตัวแทน 2. รวบรวมโปรไฟล์ 3. ใช้โปรไฟล์ในบิลด์รุ่น

ขั้นตอนที่ 1: ระบุภาระงานที่แสดงถึง

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

การระบุภาระงานที่มีประสิทธิภาพยังเป็นประโยชน์ในการติดตามประสิทธิภาพโดยทั่วไปด้วย

ขั้นตอนที่ 2: รวบรวมโปรไฟล์

การเก็บรวบรวมโปรไฟล์มี 3 ขั้นตอน ได้แก่ - การสร้างโค้ดเนทีฟด้วยเครื่องมือวัดค่า - การเรียกใช้แอปที่มีเครื่องมือวัดค่าในอุปกรณ์และการสร้างโปรไฟล์ และ - การผสาน/การประมวลผลผลลัพธ์ในภายหลังของโปรไฟล์ในโฮสต์

สร้างบิลด์ที่มีเครื่องมือวัด

ระบบจะรวบรวมโปรไฟล์โดยเรียกใช้เวิร์กโหลดจากขั้นตอนที่ 1 ในบิลด์ของแอปพลิเคชันที่เครื่องมือวัด หากต้องการสร้างบิลด์ที่มีเครื่องมือวัด ให้เพิ่ม -fprofile-generate ลงใน Flag คอมไพเลอร์และ linker แฟล็กนี้ควรควบคุมโดยตัวแปรบิลด์ที่แยกต่างหาก เนื่องจากไม่จำเป็นต้องใช้แฟล็กระหว่างบิลด์เริ่มต้น

สร้างโปรไฟล์

จากนั้นเรียกใช้แอปที่มีการวัดในอุปกรณ์แล้วสร้างโปรไฟล์ ระบบจะรวบรวมโปรไฟล์ในหน่วยความจำเมื่อเรียกใช้ไบนารีที่มีเครื่องมือวัด และเขียนโปรไฟล์ลงในไฟล์เมื่อออก อย่างไรก็ตาม จะไม่มีการเรียกฟังก์ชันที่ลงทะเบียนกับ atexit ในแอป Android แต่แอปจะหยุดทำงาน

แอปพลิเคชัน/เวิร์กโหลดต้องทํางานเพิ่มเติมเพื่อกําหนดเส้นทางสําหรับไฟล์โปรไฟล์ แล้วเรียกใช้การเขียนโปรไฟล์อย่างชัดเจน

  • หากต้องการตั้งค่าเส้นทางไฟล์โปรไฟล์ ให้เรียกใช้ __llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw %m มีประโยชน์เมื่อมีไลบรารีที่ใช้ร่วมกันหลายรายการ %m จะขยายเป็นลายเซ็นโมดูลที่ไม่ซ้ำกันสำหรับห้องสมุดนั้น ซึ่งจะทำให้มีโปรไฟล์แยกกันสำหรับแต่ละห้องสมุด ดูตัวระบุรูปแบบที่มีประโยชน์อื่นๆ ได้ที่นี่ PROFILE_DIR คือไดเรกทอรีที่เขียนได้จากแอป ดูการสาธิตเพื่อตรวจหาไดเรกทอรีนี้ขณะรันไทม์
  • หากต้องการเรียกใช้การเขียนโปรไฟล์อย่างชัดเจน ให้เรียกใช้ฟังก์ชัน __llvm_profile_write_file
extern "C" {
extern int __llvm_profile_set_filename(const char*);
extern int __llvm_profile_write_file(void);
}

#define PROFILE_DIR "<location-writable-from-app>"
void workload() {
  // ...
  // run workload
  // ...

  // set path and write profiles after workload execution
  __llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw");
  __llvm_profile_write_file();
  return;
}

หมายเหตุ: การสร้างไฟล์โปรไฟล์จะง่ายขึ้นหากภาระงานเป็นไบนารีแบบสแตนด์อโลน เพียงตั้งค่าตัวแปรสภาพแวดล้อม LLVM_PROFILE_FILE เป็น %t/default-%m.profraw ก่อนเรียกใช้ไบนารี

โปรไฟล์หลังการประมวลผล

ไฟล์โปรไฟล์อยู่ในรูปแบบ .profraw โดยต้องดึงข้อมูลจากอุปกรณ์ก่อนโดยใช้ adb pull หลังจากดึงข้อมูลแล้ว ให้ใช้ยูทิลิตี llvm-profdata ใน NDK เพื่อแปลงจาก .profraw เป็น .profdata ซึ่งจะส่งไปยังคอมไพเลอร์ได้

$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-profdata \
    merge --output=pgo_profile.profdata \
    <list-of-profraw-files>

ใช้ llvm-profdata และ clang จาก NDK เวอร์ชันเดียวกันเพื่อหลีกเลี่ยงรูปแบบไฟล์โปรไฟล์ที่ไม่ตรงกัน

ขั้นตอนที่ 3 ใช้โปรไฟล์เพื่อสร้างแอปพลิเคชัน

ใช้โปรไฟล์จากขั้นตอนก่อนหน้าในระหว่างการสร้างรุ่นของแอปพลิเคชันโดยส่ง -fprofile-use=<>.profdata ไปยังคอมไพเลอร์และโปรแกรมลิงก์ นอกจากนี้ยังสามารถใช้โปรไฟล์ได้แม้โค้ดจะมีการพัฒนา โดยคอมไพเลอร์ Clang สามารถทนต่อความคลาดเคลื่อนเล็กน้อยระหว่างแหล่งที่มาและโปรไฟล์ได้

หมายเหตุ: โดยทั่วไปแล้ว โปรไฟล์สำหรับไลบรารีส่วนใหญ่จะใช้กันตามสถาปัตยกรรม ตัวอย่างเช่น โปรไฟล์ที่สร้างจากไลบรารีบิลด์ที่ arm64 สามารถใช้กับสถาปัตยกรรมทั้งหมดได้ ข้อควรระวังคือ หากมีเส้นทางโค้ดเฉพาะสถาปัตยกรรมในไลบรารี (arm เทียบกับ x86 หรือ 32 บิตเทียบกับ 64 บิต) คุณควรใช้โปรไฟล์แยกกันสำหรับการกำหนดค่าแต่ละรายการดังกล่าว

สรุปข้อมูลทั้งหมด

https://github.com/DanAlbert/ndk-samples/tree/pgo/pgo แสดงการสาธิตจากต้นทางถึงปลายทางสำหรับการใช้ PGO จากแอป โดยให้รายละเอียดเพิ่มเติมที่ไม่ได้กล่าวถึงในเอกสารนี้

  • กฎการสร้าง CMake จะแสดงวิธีตั้งค่าตัวแปร CMake ที่สร้างโค้ดเนทีฟด้วยเครื่องมือวัด เมื่อไม่ได้ตั้งค่าตัวแปรบิลด์ โค้ดเนทีฟจะได้รับการเพิ่มประสิทธิภาพโดยใช้โปรไฟล์ PGO ที่สร้างไว้ก่อนหน้านี้
  • ในบิลด์ที่มีเครื่องมือวัด pgodemo.cpp จะเขียนโปรไฟล์เป็นการดำเนินการของภาระงาน
  • ระบบจะรับตำแหน่งที่เขียนได้สำหรับโปรไฟล์ขณะรันไทม์ใน MainActivity.kt โดยใช้ applicationContext.cacheDir.toString()
  • หากต้องการดึงโปรไฟล์จากอุปกรณ์โดยไม่ต้องใช้ adb root ให้ใช้adb สูตร ที่นี่