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

การเพิ่มประสิทธิภาพที่แนะนําโดยโปรไฟล์ (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 ที่นี่