ว่าด้วยเรื่องหน่วยความจำ สิ่งที่หลายคนมองข้าม : Optimization


" The memory is the first thing to go. "
ใครก็ไม่รู้ ได้กล่าวไว้ 
      นี่น่าจะเป็นบทความสุดท้ายสำหรับ Serial บทความเกี่ยวกับ Memory ในบทความนี้จะขอพูดถึงวิธีการแก้ปัญหาต่าง ๆ เกี่ยวกับวิธีจัดการกับหน่วยความจำอันน้อยนิดของ Microcontroller ของเรา


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

การเพิ่มประสิทธิภาพให้กับ Program memory


รูปภาพจาก https://cdn-learn.adafruit.com/downloads/pdf/memories-of-an-arduino.pdf

      เมื่อผู้อ่านทำการ compile sketch code ของคุณ ในส่วนนี้ตัว IDE มันจะบอกคุณเองว่า Program นี้มันมีขนาดใหญ่แค่ไหน เพื่อให้คุณรู้ตัวอยู่เสมอในเรื่องของ memory ที่ยังคงเหลืออยู่ แต่ก็มีบางครั้งที่เราเขียนโปรแกรมเยอะไป จนทำให้ขนาดของ Program ใหญ่เกินที่ Flash memory จะเก็บได้ทั้งหมด


ลบพวก Dead Code


      วิธีง่าย ๆ อย่างแรกเลย ลบพวก Dead Code หรือ Code ที่เราไม่ได้ใช้ออกไปซะ อย่าให้เห็นรกหูรกตา เช่น
  • Library ที่เราไม่ได้ใช้
  • Function ที่เราไม่ได้ใช้
  • Variable หรือตัวแปรที่เราไม่ได้ใช้
  • Code ที่มันไม่น่าจะเข้าถึงได้ บางทีเราอาจจะเขียนเงื่อนไขดักไว้เยอะเกินไป โดยในความเป็นจริง เงื่อนไขพวกนั้นก็ไม่ได้จำเป็นเลย
      ที่บอกไปข้างต้น ถ้ายังไม่แน่ใจว่าจะลบมันดีหรือเปล่าก็ comment ไว้ก่อน เพราะตอน compile มันจะไม่เอาส่วนนี้ไป compile ด้วย

ถ้า Code มันซ้ำกัน ก็สร้าง Function เถอะ

      ในกรณีนี้คือ ถ้าเกิดว่า Code มันซ้ำกันมากเกินกว่า 2 ครั้งก็สร้างเป็น Function ขึ้นมาเถอะ เพื่อช่วยลดขนาดของ Program memory

การเพิ่มประสิทธิภาพการใช้ SRAM

      อย่างที่รู้ ๆ กันว่า SRAM เป็นสิ่งที่มีค่าที่สุดใน Arduino เลยก็ว่าได้ ถึงแม้ว่าจะรู้ว่าปัญหาเรื่อง memory ไม่เพียงพอเป็นเรื่องใหญ่ แต่บางครั้งมันก็ยากที่จะตรวจสอบได้ว่าเราพลาดตรงไหนไป เพราะงั้น ก็ควรจะหัดเขียนให้เป็นนิสัยไปเลย เพราะบางทีเราก็ไม่รู้ว่าทำไม code เราที่ใช้ได้ แต่เพิ่มนิดเพิ่มหน่อยก็ใช้ไม่ได้แล้ว ฮ่า ๆ

ลบตัวแปรที่ไม่ได้ใช้

      ถ้าหากว่ามีตัวแปรที่ไม่ได้ใช้ ตัวแปรขยะ หรือตัวแปรที่ไม่แน่ใจว่าจะได้ใช้ ถ้าไม่ comment ก็ลบมันออกไปก่อน


ถ้าต้องการ Debug โดยใช้ Serial.print ก็ใช้ F() กับพวก String ซะ


      F() คืออะไร? มันก็คือ macro ตัวนึงที่จะบอก complier ว่าให้เก็บพวก String ทั้งหลาย เอาไว้ข้างใน PROGMEM ซึ่งเดี๋ยวอธิบายเรื่อง PROGMEM ในอีกหัวข้อ

      ทำไม้ต้องใช้ F() เพราะปรกติแล้ว เวลาเราใช้ Serial.print โดยที่ไม่ใช้ F() มันจะเก็บ String ทั้งหมดไว้ใน SRAM และถ้ายิ่งเรา print ข้อมูลที่มีจำนวนตัวอักษรมาก ๆ มันก็ยิ่งใช้พื้นที่ใน SRAM มากยิ่งขึ้น แต่เมื่อใช้ F() แล้ว มันก็จะเก็บ String เหล่านั้นไว้ใน PROGMEM ทั้งหมด และไม่ทำให้ SRAM เป็นภาระมากเกินไป



ย้ายพวก Constant Data ไปไว้ใน PROGMEM.


      จากที่เคยบอกไว้ใน ว่าด้วยเรื่องหน่วยความจำ สิ่งที่หลายคนมองข้าม ตอนที่ 1 ในส่วนของ Flash memory นอกจะเป็นที่เอาไว้เก็บ program ที่เราเขียนเอาไว้แล้วนั้น เรายังสามารถเก็บตัวแปรต่าง ๆ ไว้ในนี้ได้อีกด้วย เพียงแต่ว่าตัวแปรที่เก็บไว้ใน Flash memory นั้นไม่สามารถที่จะเปลี่ยนแปลงค่าได้ จึงเหมาะมากที่จะเก็บข้อมูลจำพวก constant ไว้ และ PROGMEM ก็คือส่วนที่จัดการเกี่ยวกับข้อมูลเหล่านั้นไว้ในส่วนของ Flash memory นั่นเอง

      ถ้ายังนึกไม่ออกว่าจะเก็บค่าอะไรบ้าง ลองนึกถึงพวก Library ที่เกี่ยวกับ LCD อะไรพวกนี้ดู ซึ่งเป็น Library ที่ต้องใช้ memory มากพอสมควร แล้วยิ่งเวลาเราจะเขียน font ขึ้นมาซักตัวจะต้องใช้ข้อมูลเยอะขนาดไหนกัน? ก็ลองเข้าไปดูตัวอย่างในนี้แล้วกัน ฮ่า ๆ OLEDDisplayFonts.h 

ดูเพิ่มเติมเกี่ยวกับ PROGMEM


ลดขนาดของ Buffer


      Buffer และ array กับการจองพื้นที่ ถ้าเราต้องการจองพื้นที่ใน array เราต้องมั่นใจว่ามันจะไม่ใหญ่เกินความจำเป็นจริง ๆ

      Buffer ใน library ในบาง Library จะมีตัวแปรที่เกี่ยวกับขนาดของ Buffer จริง ๆ แล้วในส่วนนี้เราก็สามารถปรับแต่งได้ หากต้องการ (ดูตามความจำเป็น)

      Buffer system มันยังมี Buffer บางตัวที่ถูกซ่อนไว้ในส่วนลึกของระบบเช่น Serial receive buffer ซึ่งปรกติแล้วค่า Default จะอยู่ที่ 64 byte ถ้าหากว่าข้อมูลที่รับส่งใน Serial ของเราคิดว่ายังไงก็ไม่ถึง 64 byte ก็สามารถปรับขนาดตรงนี้ลงได้ แต่ยังไงเจ้าของบล็อกก็ไม่ค่อยแนะนำที่จะไปแก้ตัวแปรใน system มากเท่าไหร่


....\Arduino-1.x.x\hardware\arduino\cores\arduino\HardwareSerial.cpp

 แล้วก็ลองหาดูบรรทัดที่เขียนว่า
#define SERIAL_BUFFER_SIZE 64


ลดขนาดของตัวแปร


    ไม่ควรใช้ float ในเมื่อ ยังสามารถใช้ int ได้อยู่ ไม่ควรใช้ int ในเมื่อ ยังสามารถใช้ byte ได้อยู่ พยายามที่จะใช้ตัวแปรที่เก็บข้อมูลให้มีขนาดน้อยที่สุดตามความจำเป็นจริง ๆ  




รู้จักเกี่ยวกับ memory


      ไม่มีอะไร แค่จะเน้นว่าถ้ารู้จักกับ memory ก็จะเข้าใจการจัดสรร memory ได้ระดับนึง ก็กลับไปอ่านใน ว่าด้วยเรื่องหน่วยความจำ สิ่งที่หลายคนมองข้าม ตอนที่ 1 แล้วก็ตอนอื่น ๆ


ใช้ EEPROM


      พูดถึง EEPROM รอบที่ร้อยละ ฮ่า ๆ ล้อเล่น ๆ ก็ตามที่บอกแหละ อีกวิธีก็คือใช้ EEPROM ก็ได้ แต่ก็ต้องดูด้วยถึงความเหมาะสม กับข้อมูลที่จะเก็บ และดูขนาดของ EEPROM ด้วย

จบแล้วเย้ Serial บทความเกี่ยวกับ memory ที่ดองมาเกือบปี ก็จบภายใน 3 วัน จริง ๆ ในใจก็ยังอยากเขียนเกี่ยวกับการ Optimize code ให้มากกว่านี้ แต่ก็คิดดูอีกทีแล้ว เอาไว้เขียนแยกบทความดีกว่า จะได้ลงลึกให้เข้าใจได้ สำหรับ Serial บทความนี้ก็เอาแค่นี้แหละ ยังไงก็ฝาก feedback เช่นเดิมนะครับ ^^

reference : https://cdn-learn.adafruit.com/downloads/pdf/memories-of-an-arduino.pdf


ความคิดเห็น

langcabler กล่าวว่า
Graton Hotel and Casino, Las Vegas, NV, United States
Try your luck at Graton Hotel 시흥 출장안마 and Casino in Las Vegas 청주 출장안마 with amenity-laden 동두천 출장샵 rooms, restaurants, exciting 안양 출장안마 shows, and the best 경상남도 출장샵 casino in town at
biosstudio กล่าวว่า
ความคิดเห็นนี้ถูกผู้เขียนลบ
biosstudio กล่าวว่า
เป็นประโยชน์มากครับ ขอบคุณ

โพสต์ยอดนิยมจากบล็อกนี้

ว่าด้วยเรื่องหน่วยความจำ สิ่งที่หลายคนมองข้าม : รู้จักกับ Memory

คณิตศาสตร์กับโปรแกรมมิ่งมันเป็นยังไงนะ ตอนที่ 1 เกริ่นพีทาโกรัส

Pointer กับตัวแปร Array นะจ๊ะ.. [Back to basic แต่ไม่ basic]