Theppitak's blog

My personal blog.

27 ธันวาคม 2551

LibThai Optimization

การปรับไปใช้ datrie 32 บิต ก็ทำให้ libthai สามารถเพิ่มคำในพจนานุกรมได้อีกเยอะ แต่ปรากฏว่า ราคาที่ต้องจ่ายไป นอกเหนือจากการใช้หน่วยความจำเพิ่มขึ้นอีกเท่าตัว (จาก 16 บิตเป็น 32 บิต) ก็คือ performance ที่ตกลงอีกราว 66% จากเวลาในการโหลดพจนานุกรมที่นานขึ้น และปริมาณการ access หน่วยความจำที่เพิ่มขึ้น

แต่การเพิ่มขนาดของ trie ก็เป็นเรื่องจำเป็นสำหรับการตัดคำไทย เพราะภาษาไทยมีจำนวนคำมากกว่าที่ trie 16 บิตจะรองรับได้ เพราะฉะนั้น ก็เลยต้องมาปรับปรุงเรื่องประสิทธิภาพ

เครื่องมือที่ใช้ช่วย ก็คือ valgrind โดยเขียนโปรแกรมง่าย ๆ ขึ้นมาลิงก์กับ libthai เพื่อทดสอบ

แต่ก่อนอื่น เนื่องจาก libthai มีการใช้งานอยู่ในระบบ ผมจึงเลี่ยงการกระทบกับระบบระหว่างทดสอบ ด้วยการติดตั้ง libthai และ datrie ฉบับ CVS ลงใน $HOME/libthai โดยตั้งตัวแปรระบบดังนี้:

$ export PATH=$HOME/libthai/bin:$PATH
$ export PKG_CONFIG_PATH=$HOME/libthai/lib/pkgconfig
$ export LD_LIBRARY_PATH=$HOME/libthai/lib

แล้วใช้ configure option สำหรับ datrie และ libthai ดังนี้:

$ ../configure CFLAGS="-Wall -g -O0" --prefix ~/libthai

คอมไพล์ ติดตั้ง ตามปกติ จากนั้นก็มาเขียนโปรแกรมทดสอบแบบง่าย:

#include <string.h>
#include <stdio.h>

#include <thai/thbrk.h>

int main ()
{
    char line [1024];
    char bline [1024];

    while (fgets (line, sizeof line, stdin)) {
        if (line [strlen (line) - 1] == '\n')
            line [strlen (line) - 1] = '\0';

        th_brk_line (line, bline, 1024, "|");
        printf ("%s\n", bline);
    }

    return 0;
}                                   

คอมไพล์โปรแกรมทดสอบ:

$ cc -o wbrk-test `pkg-config --cflags --libs libthai` wbrk-test.c

แล้วใช้ valgrind ตรวจสอบ โดยเริ่มจาก Memcheck:

$ cat testmsg | valgrind --leak-check=yes ./wbrk-test

เจอ memory leak จากการเปิดพจนานุกรมเป็น static data ซึ่งเป็นความจงใจ เพื่อให้โปรแกรมที่มาลิงก์กับ libthai ไม่จำเป็นต้องโหลดพจนานุกรมจนกว่าจะได้เรียกรูทีนตัดคำไทยจริง ๆ เป็นการโหลดเพียงครั้งเดียว แล้วใช้ในครั้งต่อ ๆ ไป แต่การทิ้ง memory leak ไว้ก็ไม่สวย โดยเฉพาะโปรแกรมที่โหลด libthai ด้วย dlopen() จะทิ้งร่องรอยไว้หลังจาก dlclose() ไปแล้ว ความจริงอยากแก้นานแล้ว ก็ถือโอกาสแก้เสียเลย (commit เข้า CVS ไปแล้ว)

หมดจากกรณีนี้ ก็ไม่มี memory leak เหลืออยู่อีกเลย ว้าว รอดตัวไป

จากนั้น ก็วัดประสิทธิภาพ หาจุดคอขวดด้วย Callgrind:

$ cat testmsg | valgrind --tool=callgrind ./wbrk-test

สำหรับผลลัพธ์ที่ Callgrind เขียนออกมานั้น คู่มือ เขาแนะนำให้เปิดดูด้วย KCachegrind แต่ทราบมาว่า Alleyoop หรือกระทั่ง Anjuta ก็ใช้เป็น frontend ได้เหมือนกัน แต่ผมมันพวกขี้เกียจ เพราะกว่าจะเซ็ตอะไร ๆ ให้พร้อมใช้ก็คงนาน อีกทั้งไม่แน่ใจว่าจะสามารถตั้ง environtment ต่าง ๆ ได้อย่างใจหรือเปล่า เลยเล่นง่าย ๆ ไปก่อน ด้วยการเปิดดูด้วย vim แล้วแกะข้อมูลตาม เอกสารทางเทคนิค ก็ทำให้เจอคอขวดได้เหมือนกัน

ที่ผ่านมา ก็ลดคอขวดไปได้สองแห่ง ลดเวลาลงได้ราว 15% ก็ต้องพยายามกำจัดจุดอ่อนต่อไป

การ optimize โดยใช้ Callgrind ช่วยในครั้งนี้ เป็นการ optimize โค้ดล้วน ๆ ด้วยการ implement ตรรกะเดิมให้เร็วขึ้น ยังไม่ใช่การทำ cut-off ในระดับตรรกะเหมือน รอบที่แล้ว ที่ทำหลังจากเปลี่ยนมาใช้พจนานุกรมภายนอก

ปล. พักหลัง ๆ นี้ ผมเขียน blog ด้วยการ "เล่าข่าวคราว" เท่านั้น ว่าทำอะไรคืบหน้าไปบ้าง โดยไม่ได้ลงรายละเอียดทางเทคนิค ก็หวังว่าการ blog โดยเพิ่มรายละเอียดด้วย จะเป็นประโยชน์กับผู้อ่านมากขึ้นบ้าง รวมทั้งกับตัวผมเองในอนาคตด้วย เป็นบันทึกกันลืม

ป้ายกำกับ:

1 ความเห็น:

แสดงความเห็น (มีการกลั่นกรองสำหรับ blog ที่เก่ากว่า 14 วัน)

<< กลับหน้าแรก

hacker emblem