03 May 2005

Altivec รอบสอง

เคยเขียนถึง Altivec หรือ Velocity Engine ซึ่งเป็นตัวประมวลผลแบบเวคเตอร์ของซีพียูตระกูล Power ซึ่งนำมาใช้ใน Mac ไปแล้วรอบนึง วันนี้กำลังพัฒนาระบบขึ้นมาใช้งานใหม่ เลยอยากรู้ว่า Altivec จะทำงานได้เร็วกว่าตัวประมวลผลแบบปกติแค่ไหน เลยลองเขียนโปรแกรมหาระยะทางแบบยูคลิดดู ซึ่งถ้าเขียนแบบธรรมดาก็จะเขียนได้ง่ายๆ แบบข้างล่างนี้

float eucidean(int len, float *x, float *y) {
 int i;
 float sum=0.0;
 
 for(i=0; i<len; i++) {
   sum += (x[i]-y[i])*(x[i]-y[i]);
 }
 return sqrt(sum);
}

โปรแกรมนี้ก็ทำงานง่ายๆ โดยเอาข้อมูลใส่ไว้ในอะเรย์แบบ float สองตัว (x กับ y) แล้วก็วนรอบคำนวณทีละตัวจนครบทุกตัว ส่วนโปรแกรมที่ทำงานแบบเวคเตอร์นั้น จะแบ่งมาคำนวณทีละ 4 ตัว ตามความสามารถของซีพียู G4 ที่ใช้อยู่ตอนนี้ เลยจะได้โปรแกรมอย่างข้างล่าง

float eucidean_altivec(int len, float *x, float *y) {
 int i=0,l;
 vector float vx,vy,vz,vsum=(vector float)vec_splat_s8(0);
 float sum=0.0;
 
 while(len>0) {
  /* Warning!!! size of float array must be divided by 4 */
  vx = (vector float)vec_ld(0, x+i);
  vy = (vector float)vec_ld(0, y+i);
  vz = vec_sub(vx, vy);
  vsum = vec_madd(vz, vz, vsum);
  len -= 4;
  i += 4;
 }
 vsum = vec_add(vsum, vec_sld(vsum,vsum,4));
 vsum = vec_add(vsum, vec_sld(vsum,vsum,8));
 vec_ste(vsum, 0, &sum);
 return sqrt(sum);
}

โปรแกรมนี้จะเริ่มจากการโหลดข้อมูลจากอะเรย์ไปเก็บไว้ในเวคเตอร์ (vx, vy) โดยใช้คำสั่ง vec_ld จากนั้นเอามาลบกันด้วย vec_sub เก็บไว้ที่ vz เสร็จแล้วก็เอายกกำลังสอง (คูณกันเอง) แล้วบวกเก็บไว้ที่ vsum สุดท้ายจะได้เวคเตอร์ที่เก็บผลรวมไว้ แต่ยังแยกเป็นสี่กลุ่ม ก็เลยเอา vsum มาเลื่อนไปมา ด้วยคำสั่ง vec_sld แล้วก็เอามาบวกกัน สุดท้ายจะได้ผลรวมอยู่ที่ตำแหน่งแรกสุด ซึ่งก็คือค่าที่ต้องการหา

ลองเทียบความเร็วด้วยการคำนวณหาระยะทางโดยให้ x และ y เป็นจุดในพื้นที่ 120 มิติ แล้วให้ทำงานหนึ่งล้านครั้ง โดยไม่มีการ optimize ตอนคอมไพล์ ได้เวลาที่แตกต่างกันเยอะพอสมควร โดยแบบธรรมดาจะใช้เวลา

real    0m4.989s
user    0m4.800s
sys     0m0.020s

ส่วนแบบใช้ Altivec ใช้เวลา

real    0m1.303s
user    0m1.260s
sys     0m0.020s

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

2 comments:

Anonymous said...

profiler คืออะไรเหรอครับ

Anonymous said...

โปรแกรมสำหรับตรวจเช็ค จับเวลา การทำงานของโปรแกรม ซึ่งจะแจกแจงให้ได้ว่า จากข้อมูลที่เราใส่เข้าไป เสียเวลาทำงานที่ ฟังก์ชันไหนเท่าไหร่ ทำให้รู้ว่าคอขวดอยู่ตรงไหน จะได้ไปแก้ที่ตรงนั้น ถ้าของ GNU ก็มี gprof (GNU Profiler)