protect

ถ้าเอาบทความไปเผยแพร่แล้วไม่ให้เครดิต ดำเนินคดีด้วย พรบ. คอมพิวเตอร์ฉบับใหม่ ขั้นสูงสุดและไม่ยอมความครับ

วันจันทร์ที่ 31 สิงหาคม พ.ศ. 2558

Common Type System (CTS) ตอนที่ 3


เรามาต่อกันตอนที่ 3 กันเลยน่ะครับ

.get_thisIsProperty : string()
.set_thisIsProperty : void(string)
เป็นคำสั่งสำหรับ get กับ set ตัวแปรที่เป็นชนิด property




ถ้าเทียบกับภาษา C# ก็คือชุดคำสั่งนี้ครับ

      public string thisIsProperty
        {
            get { return ""; }
            set {}
        }

จะเห็นว่า get return ""; } เมื่อแปลงเป็นภาษา IL ก็คือ คำสั่ง .get_thisIsProperty : string() (หมายเลข 1 ของรูป)  โดยที่ .get_thisIsProperty เป็นชื่อ method ของ IL code

หลักกการของ C# compiler คือ เมื่อ compile C# code ไปเป็นภาษา IL ตัว C# Compiler ก็จะสร้าง method เป็นของตัวเอง โดยชื่อของ method ก็จะเอาคำว่า "get_" มาใส่นำหน้าชื่อตัวแปรชนิด property นั้นเองครับ สำหรับ string() เป็นตัวบอกว่าไม่มีพารามิเตอร์รับเข้าที่ method และ method ก็จะ return ค่าเป็น string ให้กับ caller หรือ function ที่เรียกใช้ method นี้

เมื่อ double click ที่บรรทัด .get_thisIsProperty : string() ในโปรแกรม ILDasm เราก็จะเห็นภาษา IL ของ method ดังรูป



และคำสั่ง set {} เมื่อแปลงเป็นภาษา IL ก็คือคำสั่ง .set_thisIsProperty : void(string)(หมายเลข 2 ของรูป) 

.set_thisIsProperty เป็นชื่อ method และ void(string) บอกให้รู้ว่า method นี้ รับพารามิเตอร์เข้ามาเป็น string และไม่มีการ return ค่ากลับออกไปให้ caller

เนื่องจากใน code C# ของตัวอย่างเราไม่ได้ทำอะไร เมื่อ double click ที่บรรทัด .set_thisIsProperty : void(string) ใน ILDasm เราจึงเห็นว่าการทำงานของ function นี้ไม่ได้ทำอะรเลย




สำหรับ thisIsProperty : instance string() (หมายเลข 3 ของรูป) เป็นการเก็บ information ของ property ที่ชื่อ thisIsProperty โดยเมื่อ double click ที่คำสั่งนี้  เราจะได้ information ตามรูป



ภายใน IL code ของ property thisIsProperty จะเห็นคำสั่ง .get ที่จะบอกว่าให้ runtime ไป execute method ชื่อ get_thisIsProperty ของ class Program ใน namespace CTS เมื่อ caller อ่านค่าจาก thisIsProperty
และคำสั่ง .set ที่จะไป execute method ที่ชื่อ set_thisIsProperty ของ class Program ใน namespace CTS เมื่อ caller มีการ assign ค่าให้กับ thisIsProperty


.thisIsMethod : void()
.thisIsMethod : void(int32)
คือ method โดยมีชื่อเหมือนกัน แต่ พารามิเตอร์ หรือ signature ที่ต่างกัน



ถ้าเทียบกับภาษา C# ก็คือชุดคำสั่งนี้ครับ

         public void thisIsMethod()
        {

        }

        public void thisIsMethod(int param)
        {

        }

เราสามารถเข้าไปดู IL code ของ method นี้ ด้วยการ double click ไปที่ .thisIsMethod : void() หรือ .thisIsMethod : void(int32) เนื่องจากใน code ตัวอย่างเราไม่ได้ใส่อะไรใน function ดังนั้น code IL ของทั้งสอง method จึงยังไม่มีอะไรครับ นอกจาก nop กับ ret


พบกันใหม่ตอนที่ 4 ตอนจบน่ะครับ
TuChay

วันศุกร์ที่ 28 สิงหาคม พ.ศ. 2558

สวัสดี Linux


ครับ ไม่ผิดหรอกครับสำหรับบทความนี้ "สวสัดี Linux" ก่อนอื่นต้องขอชี้แจงก่อนว่า บทความที่เกี่ยวกับ ภาษา C#, IL และ .Net Framework ก็จะยังเขียนต่อไปเรื่อยๆ น่ะครับ ไม่ได้หยุดเขียนแต่อย่างใด

เนื่องจาก C# เป็นงานที่ทำแต่ Linux เป็นงานอดิเรกที่ผมรัก ผมเล่น Linux ตั้งแต่ X Window ยังไม่เกิด boot เครื่องมาก็เป็นแต่หน้าจอดำๆ แต่ก็เป็นอะไรที่สนุกครับ เลยจะรื้อฟื้นความจำเอามาเขียนเป็นบทความเพื่อคนที่สนใจและก็เพื่อตัวผมเองจะเอามาอ้างอิงกรณีที่ลืม

สิ่งที่ผมจะเขียนเกี่ยวกับ Linux ในช่วงแรกๆ ก็คงจะเป็นเรื่องเกี่ยวกับ Shell เพราะเป็นพื้นฐานที่สุด โดยจะควบรวมไปถึงการเขียน Shell script ด้วยครับ หลังจากนั้นก็ยังนึกไม่ออกเหมือนกันว่าจะเขียนเกี่ยวกับอะไรดี .... ลองติดตามดูล่ะกันน่ะครับ

TuChay


วันพฤหัสบดีที่ 27 สิงหาคม พ.ศ. 2558

Common Type System (CTS) ตอนที่ 2


ในตอนนี้เราลองมาดูตัวอย่าง code ของ C# เมื่อเราเขียนโปแกรมตาม standard ของ Microsoft แล้ว ภาษา IL ที่เราได้จะเป็นอย่างไรน่ะครับ

using System;

namespace CTS
{
    class Program
    {
        public int thisIsField;
       
        //This is constructor
        public Program()
        {

        }

        //This is destructors
        ~Program()
        {

        }

        public string thisIsProperty
        {
            get { return ""; }
            set {}
        }


        public void thisIsMethod()
        {

        }

        public void thisIsMethod(int param)
        {

        }

        public event EventHandler thisIsEvent;

        //This is indexer
        public string this[int inderxer]
        {
            get { return ""; }
            set { }
        }

        static void Main(string[] args)
        {
        }
    }
}


จากตัวอย่าง code ลอง compile เราจะได้ file นามสกุล .EXE ในที่นี้ผมได้ชื่อว่า CTS.exe ถ้าลองเปิด CTS.exe ด้วยโปรแกรม ILDasm ก็จะได้ดังรูปน่ะครับ



วิธีการใช้ ILDasm ผมได้อธิบายที่ Execute โปรแกรม Managed Code ตอนที่ 1 

เรามาดูที่ command พื้นฐานกันน่ะครับ สำหรับ command ที่ผมยังไม่อธิบายในตอนนี้เป็น command ที่ค่อนข้างยาก ผู้อ่านจะต้องทำความเข้าใจพื้นฐานของ IL และพื้นฐานการจัดการ memory ของ .Net Framework ก่อนแต่ผมจะอธิบาย command ที่เหลือในบทความถัดไป ใจเย็นๆ น่ะครับ

.ctor : void() 
.ctor เป็น constructor ของ class ถ้าเรา double click ที่ บรรทัด .ctor : void() ก็จะได้ดังรูป


จากในรูปข้างบนจะเป็นภาษา IL ของ constructor ของ Type ที่ชื่อ Program จะเห็นคำสั่ง nop ซึ่งผมได้อธิบายไว้แล้วที่ Debug VS Release

ที่บรรทัดแรกเราจะเห็น .method เพื่อที่จะบอกให้ runtime รู้ว่านี้เป็นสมาชิกของ Type ชนิด method ผมได้อธิบายเกี่ยวกับชนิดของสมาชิกของ Type ที่ Common Type System (CTS) ตอนที่ 1  ลองย้อนไปอ่านดูน่ะครับ

ถ้าเทียบกับภาษา C# ก็คือชุดคำสั่งนี้ครับ

       public Program()
        {

        }



.Finalize : void() 
ตัวนี้เป็น destructors ของ class สามารถ double click เพื่อเข้าไปดูภาษา IL ของ function นี้ได้เหมือนกัน

ถ้าเทียบกับภาษา C# ก็คือชุดคำสั่งนี้ครับ

         ~Program()
         {

         }




.thisIsField: public int32 
ตัวนี้จะเป็นตัวบอก runtime ว่าเป็นสมาชิกชนิด field และมี data type เป็น int 32 bit ถ้าเรา double click ที่ บรรทัด .thisIsField: public int32 จะเห็นว่าที่นำหน้าบรรทัดแรก ระบุเป็น .field และไม่มี function การทำงานสำหรับตัวแปรนี้



ถ้าเทียบกับภาษา C# ก็คือชุดคำสั่งนี้ครับ

               public int thisIsField;


เริ่มสนุกกับภาษา IL แล้วใช่ไหมครับ ถ้าอย่างนั้นพบกันใหม่ในตอนที่ 3 ครับ
TuChay

วันอังคารที่ 25 สิงหาคม พ.ศ. 2558

Common Type System (CTS) ตอนที่ 1


จากบทความที่ผ่านมาแสดงให้เห็นว่า ไม่ว่าเราจะเขียนโปรแกรมด้วยภาษาอะไรในชุดของ .Net Framework ตัว compiler จะทำหน้าที่เป็นตัวเช็คไวยกรณ์ (syntax) แล้วจึงแปลง code ต้นฉบับมาเป็น Managed code ที่มีภาษา IL อยู่ข้างใน ดังนั้นเราหรือใครๆ ก็สามารถเขียนภาษาขึ้นมาเองได้ สิ่งที่ต้องทำเพียงแค่สร้าง compiler ที่แปลง ภาษาของเรานั้น ไปเป็น Managed code 

Microsoft ได้ลงทะเบียนที่ ecma เพื่อที่จะนำ .Net Framework ไปเป็นมาตรฐานเพื่อให้นักพัฒนาทั่วโลกสามารถเขียนภาษาของตัวเอง โดยเอกสารฉบับเต็มสามารถอ่านได้ที่ http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf 

หนึ่งในมาตรฐานที่ Microsoft ได้กำหนดไว้คือ Common Type System (CTS) ซึ่งภาษาใดๆ ก็ตามแต่ที่จะมาใช้ runtime ของ .Net Framework จะต้องทำตามกฏของ Common Type System โดยตัวโปรแกรมจะต้องเป็นรูปแบบของ Data Type คือในโปรแกรมจะต้องมีอย่างน้อย 1 Data Type 

Data Type ในที่นี้หมายถึง class น่ะครับ Microsoft จะมองว่า 1 class เป็น 1 Data Type

โดยที่ Type ที่จะใช้ runtime ของชุด .Net Framework จะต้องมี member ใน Type ที่มีคุณลักษณะดังนี้

1) field 
เป็นสมาชิกที่มีแค่ชนิดของ data type และก็ชื่อ

2) method 
เป็น function ที่มีการดำเนินงานภายใน Method จำเป็นต้องมี ชื่อ, signature และ modifiers

signature หรือ parameter ที่ส่งเข้ามาใน Method จะต้องระบุจำนวนและชนิดของ signature.

3) property
มีลักษณะเหมือนก้บ field แต่สามารถทำงานได้เหมือน method เราสามารถ set property ให้เป็น read only หรือ write only

4) event
สามารถที่จะมีกลไก การแจ้งเตือน ระหว่าง object กับ object

นอกจากนี้ Microsoft ยังกำหนด การเข้าถึงสมาชิกใน Type หรือ modifiers ดังนี้

1) Private
การเข้าถึงสมาชิกใน Type จะใช้ได้เฉพาะเพาะสมาชิกใน Type เท่านั้น

2) Family
การเข้าถึง สมาชิกใน Type จะต้องเป็นสมาชิกใน Type และมาจากการสืบถอด Type เท่านั้น 

ในภาษา C# เราจะใช้ protected เป็น modifiers ชนิด family

3) Family and assembly
member ชนิดนี้จะไม่มีใน C# แต่จะมีเฉพาะในภาษา IL เท่านั้น

4) Assembly
เป็นสมาชิกที่อนุญาติให้เข้าถึงได้ใน assembly เดียวกัน 

ในภาษา C# จะใช้ internal เป็น modifiers ชนิดนี้

5) Family or assembly
การ เข้าถึง สมาชิกใน Type จะต้องเป็นสมาชิกใน Type และมาจากการสืบถอด Type ภายใน assembly เท่านั้น 

ในภาษา C# เราจะใช้ protected internal เป็น modifiers ชนิด family or assembly

6) Public
สมาชิกใน Type สามารถ access ได้ทุกๆ ที และทุกๆ assembly.


พบกับตอนที่ 2 ในบทความหน้าครับ

TuChay

วันศุกร์ที่ 21 สิงหาคม พ.ศ. 2558

Hello World ด้วยภาษา IL


จากบทความที่ผ่านมาทำให้เรารู้จักกับ Managed mode ในแบบของ .Net Framework ซึ่งไม่ว่าจะใช้ภาษาอะไรในชุดของ .Net Framework ตัว compiler จะ compile code เพื่อที่จะได้ Managed code ที่ภายในบรรจุภาษา IL

ในบทความนี้ผมจะพาผู้อ่านมาลองเขียนภาษา IL แบบง่ายๆ กันดูครับ ตัวอย่างทั่วไปก็คงหนีไม่พ้น Hello World

เราดูตัวอย่าง code ข้างล่างกันเลยครับ


 //Test.IL

.assembly extern mscorlib {}

.assembly Test
{
    .ver 1:0:1:0
}

.method static void main() cil managed
{
    .entrypoint
  
    ldstr "Hello World from IL Assembly Language."
  
    call void [mscorlib]System.Console::WriteLine (string)
    ret
}


Code นี้สามารถเขียนด้วยโปรแกรม text editor ธรรมดาเช่นโปรแกรม Notepad จากนั้น save ลง file ชื่อ "HelloWorld.il" 

เรามาดูคำอธิบายทีล่ะบรรทัดน่ะครับ


 //Test.IL

เครื่องหมาย // เป็นตัวบอกให้ compiler รู้ว่านี้คือ comment ตัว compiler จะไม่ compile code ในส่วนนี้ วิธีใช้ comment ก็จะเหมือนกับภาษาของ .Net Framework ทั่วๆ ไปครับ เช่น คำสั่ง /* .... */ สำหรับ comment เป็น block 

.assembly extern mscorlib {}

ภาษา IL จะมีจุด (.) หรือ period sign ไว้เป็นตัวนำหน้าคำสั่ง สำหรับคำสั่ง .assembly เป็นตัวบอกให้ compiler รู้ว่าเราจะมีการเรึยกใช้ library ภายนอก ในตัวอย่างคือ  mscorlib.dll


 .assembly Test
{
    .ver 1:0:1:0
}

สำหรับคำสั่งนี้ จะเป็นการใส่รายละเอียดของ Managed module จากตัวอย่างเป็นการกำหนดให้ module มีชื่อว่า Test และระบุ version ของ module เป็น version 1.0.1.0 ด้วยคำสั่ง .ver 1:0:1:0
สำหรับคำสั่ง  .ver สามารถเปรียบเทียบกับ code ของ C# คือ [assembly: AssemblyVersion("1.0.1.0")] คำสั่งนี้จะอยู่ใน File ที่ชื่อ AssemblyInfo.cs ใน folder Property ของ Project


.method static void main() cil managed
คำสั่งนี้จะบอกให้ compiler รู้ว่า ตั้งแต่ { จนถึง } คือ code ของ function ที่ชื่อ main() 
cil managed ก็บอกให้รู้ว่า function main เป็นชนิด managed code 
สามาถเปรียบเทียบกับ code ของ C# ได้คือ static void Main()

.entrypoint บอกให้ compiler รู้ว่า method นี้เป็น entry point สำหรับ entry point ผมได้อธิบายไปแล้วที่ http://tuchay.blogspot.com/2015/07/unmanaged-code-vs-managed-code-2.html


ldstr "Hello World from IL Assembly Language."

คำสั่งนี้เก็บตัวอักษรลงใน stack memory โดยที่ไม่ได้เก็บลงตัวแปร


call void [mscorlib]System.Console::WriteLine (string)

บรรทัดนี้ก็จะเป็นการเรียกใช้ Console.WriteLine ของ namespace System ที่ป็น library อยู่ใน file mscorlib.dll

parameter ที่ใส่ลงใน WriteLine ไม่ได้กำหนดเป็นตัวแปร นั้นหมายถึง compiler จะไปเอามาจาก stack memory โดยดึงมาจากส่วนบนสุดของ memory (เราเพิ่งใส่ string ไปใน stack memory ด้วย คำสั่ง ldstr)

เมื่อดึงมาแล้วก็จะทำการแสดงผลในหน้าจอว่า "Hello World from IL Assembly Language."

คำสั่ง ret เป็นตัวบอก compiler ว่า method นี้สิ้นสุดแค่นี้ ตรงนี้สำคัญน่ะครับถึงแม้ว่า method main จะมี return function เป็น void หมายถึงไม่มีอะไรที่ต้อง return ออกไป ภาษา IL ยังจำเป็นต้องมีคำสั่ง ret ครับถ้าไม่ใส่เราจะได้ error ต้อง runtime ครับ

หลังจากเขียน code แล้ว save ลง file test.il  เราจะได้ IL code แล้ว แต่ file นี้ยังไม่สามารถ execute ได้ อย่าลืมน่ะครับ โคงสร้างของ managed code ต้องประกอบด้วย 4 ส่วนที่สำคัญรายละเอียดผมอธิบายไปแล้วที่  http://tuchay.blogspot.com/2015/07/unmanaged-code-vs-managed-code-2.html

เราสามารถสร้างอีก 3 ส่วนที่เหลือ ได้ด้วยคำสั่ง ilasm ดูตัวอย่างรูปข้างล่างครับ



จากนั้นเราก็จะได้ Managed file ที่มีครบทั้ง 4 ส่วนที่มีชื่อ file ว่า test.exe แล้วน่ะครับ เมื่อเรา execute test.exe ก็จะได้ผลลัพท์ดังรูปข้างล่างครับ



บทความต่อๆ ไปผมจะอธิบายเรื่อ CLR กับ IL โดยจะค่อยๆ เจาะลึกไปเรื่อยๆ น่ะครับ

พบกันใหม่บทความหน้าครับ
TuChay



วันอังคารที่ 18 สิงหาคม พ.ศ. 2558

ทดสอบ ประสิทธิภาพของ JITCompiler ตอนที่ 2


มาต่อจากบทความที่แล้วกันเลยน่ะครับ

3. QueryPerformanceCounter ของ Kernel32.dll
ระบบปฏิบัติการ Windows มี UnManaged library สำหรับให้นักพัฒนาได้นำไปใช้กัน function QueryPerformanceCounter ก็เป็นหนึ่งในนั้นโดย function นี้จะอยู่ใน file Kernel32.dll 

วิธีการใช้ QueryPerformanceCounter ตามตัวอย่าง code ข้างล่างเลยครับ 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace HelloWorld
{

    class Program
    {
        [DllImport("Kernel32.dll")]
        public static extern void QueryPerformanceCounter(ref long freq);

        [DllImport("Kernel32.dll")]
        public static extern void QueryPerformanceFrequency(ref long ticks);

        static void Main(string[] args)
        {
            for (int NumberOfTry = 0; NumberOfTry < 3; NumberOfTry++)
            {
                TestCounter();
                Console.WriteLine("Press any key to do one more time");
                Console.ReadLine();
            }
        }


        static void TestCounter()
        {
            long frequency = 0;
            long start = 0, stop = 0;
            Decimal microsec = new Decimal(1.0e6);
            Decimal nanosec = new Decimal(1.0e9);


            QueryPerformanceFrequency(ref frequency);
            QueryPerformanceCounter(ref start);

            long total = 0;
            for (int i = 0; i < 1000000; i++)
                total += i;

            QueryPerformanceCounter(ref stop);

            double duration = (( (double)(stop - start) / (double)frequency) ) ;
           
            Console.WriteLine("Duration (microsecond) = " + ((duration * (double)microsec)).ToString());
            Console.WriteLine("Duration (nanosecond) = " + (duration * (double)nanosec).ToString());

        }
    }
}


เรามาลองดู code ที่ล่ะส่วนกันน่ะครับ

        [DllImport("Kernel32.dll")]
        public static extern void QueryPerformanceCounter(ref long freq);

        [DllImport("Kernel32.dll")]
        public static extern void QueryPerformanceFrequency(ref long ticks);



จาก code ข้างบนจะเป็นการบอก JITCompiler ว่าเราจะมีการเรียกใช้ function ที่ชื่อ QueryPerformanceCounter และ QueryPerformanceFrequency จาก library file ที่ชื่อว่า Kernel32.dll เนื่องจาก library Kernel32.dll เป็นชนิด UnManaged Code จึงต้องกำหนด Attribute ของ function ให้ไปเรียกใช้ตัว code ที่ Kernel32.dll หมายความว่าเมื่อ C# เรียกใช้ function  QueryPerformanceCounter หรือ QueryPerformanceFrequency JITCompiler จะไปเรียกใช้ function QueryPerformanceCounter หรือ QueryPerformanceFrequency จาก Kernel32.dll


            Decimal microsec = new Decimal(1.0e6);
            Decimal nanosec = new Decimal(1.0e9);


code ข้างบนสามารถเขียนแทนได้ด้วย


            Decimal microsec = 1000000;
            Decimal nanosec = 1000000000;



สำหรับผมเลข 0 มันเยอะไปเลยเขียนให้ย่อๆ เพื่อนอ่าน code ง่ายและลดความผิดพลาดในการพิมพ์ครับ

  
สำหรับคำสั่ง QueryPerformanceFrequency(ref frequency); จะเป็นการถาม frequency ของ performance-counter ของระบบปฏิบัติการ ค่านี้จะถูก setup ทุกครั้งที่มีการเปิดเครื่องคอมพิวเตอร์ หน่วยที่ได้จะเป็นจำนวบนับต่อวินาที (counts per second)


คำสั่ง QueryPerformanceCounter(ref start); เป็นการบอกให้เริ่มต้นจับเวลาและคำสั่ง
QueryPerformanceCounter(ref stop); เป็นการสั่งให้หยุดจับเวลา


ถ้าเราเอา start กับ stop มาลบกันจะเป็นจำนวน counts ที่ CPU ได้ทำงานในช่วงที่ counter start จนกระทั่ง counter stop โดยที่มีหน่วยเป็น counts

ดังนั้นเมื่อนำเอาจำนวน start - stop แล้วเอามาหาร frequency (ที่มีหน่วยเป็น counts per second) ค่าที่ได้จึงเป็นระยะเวลาระหว่าง start ถึง stop ในหน่วยของวินาที



ผลลัพท์ที่ได้จากการรัน code




จะเห็นว่าเมื่อเรา execute function ครั้งแรกจะกินเวลามากกว่าเป็นเพราะ CPU ต้องเสียเวลา compile IL code ตอน runtime แต่หลังจากตรั้งที่ 2 เป็นต้นไปเวลาในการทำงานก็จะน้อยลง สิ่งที่สังเกตุได้คือเวลาที่ compile IL code น้อยมากๆ ในความเห็นของผมเป็นตัวเลขที่ผมยอมรับได้ครับ

พบกันใหม่บทความหน้าครับ
TuChay


วันเสาร์ที่ 15 สิงหาคม พ.ศ. 2558

ทดสอบ ประสิทธิภาพของ JITCompiler ตอนที่ 1

จากบทความก่อนหน้านี้เราได้ทราบแล้วว่า CLR ของ .Net Framework จะเรียก function JITCompiler เพื่อ compile IL code ไปเป็น Native CPU ทุกๆ ครั้งที่โปรแกรมถูก execute ถ้าคนมีพื้นฐาน C/C++ อาจจะสงสัย performance ตอนที่โปรแกรมถูกเรียกใช้งานจะช้าหรือเปล่า บทความนี้เราจะมาวัด performance หรือประสิทธิภาพ ความเร็วของ JITCompiler กันครับ

ก่อนที่เราจะไปวัดประสิทธิภาพของ JITCompiler เรามารู้จักเครื่องมือวัดที่เราสามารถใช้ได้ก่อนครับ ปกติเครื่องมือวัดของเราสามารถใช้ได้ดังนี้

1.TimeSpan
   เรามาทดลองใช้ TimeSpan ในการวัด performance ของ code ข้างล่างดูน่ะครับ

        public static void TestCounter()
        {
            DateTime start = DateTime.Now;
            Console.WriteLine(start.ToString("dd/MM/yyyy hh:mm:ss:fff"));

            int counter = 0;
            for (int i = 0; i < 100; i++)
                counter++;

            DateTime stop = DateTime.Now;
            Console.WriteLine(stop.ToString("dd/MM/yyyy hh:mm:ss:fff"));
            TimeSpan duration = DateTime.Now.Subtract(start);
            Console.WriteLine(duration.Milliseconds + " millisecond");

        }

        public static void Main(string[] args)
        {
            for (int NumberOfTry = 0; NumberOfTry < 3; NumberOfTry++)
            {
                TestCounter();
                Console.WriteLine("Press any key to do one more time");
                Console.ReadLine();
            }

        }


  นี้คือ ผลที่ได้จากการ execute โปรแกรมน่ะครับ



   จากผลการทดลองจะเห็นว่าเมื่อเรา execute function TestCounter() ครั้งที่ 1 เราต้องใช้เวลาประมาณ 42 millisecond แต่พอเรา execute ครั้งที่ 2 และครั้งที่ 3 ผลการ execute กลับใช้เวลาน้อยกว่า 1 millisecond ซึ่งตรงกับที่เราเข้าใจว่าเมื่อถูก execute ครั้งแรก JITCompiler จะ compile IL code ไปเป็น Native CPU code และพอ execute ครั้งที่สองเป็นต้นไปก็เป็นการเรียกใช้ Native CPU code ที่ถูก compile เสร็จแล้วได้เลย

   ข้อเสียของ TimeSpan คือ หน่วยที่เล็กที่สุดที่วัดได้คือ millisecond เนื่องจากเราอยากรู้ว่าการ execute function TestCounter() ครั้งที่ 2 กับครั้งที่ 3 ใช้เวลาเท่าไร ด้งนั้น TimeSpan จึงไม่ใช่เครื่องมือวัดที่ละเอียดพอครับ

2.Stopwatch
   Stopwatch ที่มีอยู่ใน .Net Framework ต่ำกว่า version 4.5 จะมีความสามารถเหมือนกับ TimeSpan คือสามารถจับระยะเวลาความแตกต่างได้แค่ระดับ millisecond เท่านั้น
   แต่ Stopwatch ที่มีอยู่ใน version 4.5 ขึ้นไป สามารถวัดได้ในระดับ microsecond แต่ CPU และ Windows ที่ใช้ execute โปรแกรมจะต้องเป็นชนิด high frequency เท่านั้นถึงจะจับความแตกต่างในระดับ microsecond ได้

    เนื่องจาก Visual Studio ของผมยังเป็น version 2013 อยู่ผมจึงไม่สามารถเขียน code ของ Framework 4.5 ได้ แต่ผู้อ่านสามารถดูได้จากตัวอย่างนี้น่ะครับ

    ถ้าอยากดู source code ของ Stopwatch ของ .Net Framework สามารถดูได้ที่ link นี้ครับ

    ด้วยข้อจำกัด Stopwatch ในเรื่องของ require .Net Framework 4.5 ขึ้นไปและต้องการ CPU กับ Windows ที่เป็น high frequency ดังนั้น Stopwatch จึงยังไม่ใช่ตัวเลือกที่ดีพอสำหรับเรา

บทความหน้าผมจะแสดงให้ดูถึงเครื่องมือวัดในระดับ microsecond โดยใช้ UnManaged code ของ library พื้นฐานของ Windows ซึ่งจะเป็นยังไงพบกันใหม่บทความหน้าครับ
TuChay


วันพุธที่ 12 สิงหาคม พ.ศ. 2558

Debug VS Release


จากบทความที่แล้วผมได้อธิบายขั้นตอนการ execute โปรแกรมชนิด Managed Code ของ .Net Framework เราจะเห็นว่าขั้นตอน compile code IL ไปเป็น Native CPU ซึ่งจะเริ่มต้นทำตอน execute โปรแกรมอาจจะใช้เวลานาน ดังนั้นการ optimize code จึงเป็นสิ่งที่จำเป็นอย่างยิ่งเมื่อเรา release โปรแกรม เป็น official version.

compiler ในชุดของ .Net Framework มี parameter 2 ตัวสำหรับให้ใช้ compile โปรแกรมที่เรากำลังพัฒนา parameter ทั้งสองตัวนี้ จะช่วย compiler optimize IL code และ Native CPU เพื่อให้การ execute โปรแกรมมีประสิทธิภาพมากที่สุด

parameter ทั้ง 2 ตัวนี้ ได้แก่

1) optimize(+/-)
ด้วยความสามารถของโปรแกรม Visual Studio จะสามารถอนุญาติให้เรา debug โปรแกรมให้ทำงานทีล่ะบรรทัดหรือกระโดดไป execute บรรทัดที่เราต้องการ ก่อนอื่นต้องเข้าใจก่อนว่าช่วงที่เรากำลัง debug โปรแกรมด้วย Visual Studio เป็นการทำงานรวมกันระหว่างภาษา IL กับภาษา Native CPU การทำเช่นนี้ได้ compiler ของ .Net Framework จำเป็นจะต้อง modify IL code โดยใช้ชุดคำสั่ง NOP (Non operation - กรณีการ debug code ที่ละบรรทัด) ยิ่งมาการ set break point มากหรือ run single step (debug code ทีล่ะบรรทัด) มากจำนวนชุดคำสั่ง NOP ใน IL code ก็จะมีมากขึ้นตามไปด้วย

การ debug code ด้วยการกระโดดไปทำงานทีบรรทัดอื่นๆ หรือการกระโดดเข้าไปในชุดคำสั่ง loop เช่น for loop, while loop ตัว compiler ก็จะใส่ชุดคำสั่งที่เรียกว่า branch instruction ลงไปใน IL code เพื่อที่จะให้ Visual Studio สามารถ debug code ได้ถูกต้อง

ตัวอย่างที่เห็นได้ชัดของ branch instruction คือ debug code ของ function ชนิด recursive เช่นตัวอย่าง code ข้างล่างครับ

        static void Main(string[] args)
        {
            Console.WriteLine(Recursive(10).ToString());

            Console.ReadLine();
        }

        static int Recursive(int counter)
        {
            int nextCounter = counter - 1;
            if (counter > 0)
            {
                return ( counter * Recursive(nextCounter));
            }
            else
            {
                return 1;
            }
        }
  
ถ้ามีการ set break point ที่คำสั่ง if (counter > 0)ตัว branch instruction จะเป็นตัวบอก Visual Studio ทราบว่าเป็นการ debug function Recursive ของ counter ตัวที่เท่าไร

โดยปกติโปรแกรมที่เราส่งไปให้ลูกค้าไม่จำเป็นต้องมีชุดคำสั่ง NOP และชุดคำสั่ง branch instruction เลย การที่จะบอก compiler ไม่ให้ใส่ชุดคำสั่ง NOP กับ branch instruction ด้วยการใส่ parameter optimize+ ซึ่งจะเป็นการช่วยให้ execute file (file นามสกุล EXE) มีขนาดเล็กลงเพราะไม่มีชุดคำสั่งดังกล่าว

ตอนที่เรา debug code ด้วย Visual Studio ตัว compiler จะถูก compile ด้วย parameter /optimize-


2 debug(full/pdbonly)
การ debug code ของโปรแกรม Visual Studio การใส่ NOP กับ branch instruction ยังไม่สามารถ debug code ได้ ทุกครั้งที่มีการ compile code ตัว compiler จึงได้สร้าง file นามสกุล PDB (Program Database) file PDB จะเป็นตัวเก็บข้อมูลของ address ของ Native code กับ ที่อยู่ของ C# code (ก่อนเป็น IL code)

การ set parameter /debug:full จะเป็นการบอก JIT compiler ให้ compile IL code ในส่วนของ NOP กับ branch instruction ด้วย

การ set parameter /debug:pdbonly จะเป็นการบอก JIT compiler สร้าง file PDB อย่างเดียวและใม่ต้อง compile ชุดคำสั่ง NOP กับ branch instruction และไม่สร้าง DebuggableAttribute นั้นหมายถึงเราจะ debug code ไม่ได้ครับ

file PDB นี้จำเป็นสำหรับ Visual Studio แต่ไม่จำเป็นสำหรับลูกค้า เราไม่จำเป็นต้องใช้ file นี้ลงไปใน official version ครับ

บทสรุป
Visual Studio มี mode สำหรับการ compile code อยู่ 2 mode คือ Debug กับ Release

การ compile code ด้วย mode Debug คือการ set parameter /optimize- กับ /debug:full

การ compile code ด้วย mode Release คือการ set parameter /optimize+ กับ /debug:pdbonly


พบกันใหม่บทความหน้าครับ
TuChay

วันอังคารที่ 4 สิงหาคม พ.ศ. 2558

Execute โปรแกรม Managed Code ตอนที่ 2


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

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World");
            Console.WriteLine("Good Bye");
        }
    }
}

จาก code ผมใช้ C# compiler compile code จนได้ file HelloWorld.exe เมื่อเรา execute โปรแกรมในที่นี้ด้วยคำสั่ง

c:\>HelloWorld.exe

นี้คือสิ่งที่เกิดขึ้นในโลกของ .Net Framework

1) Step 1
ระบบปฏิบัติการ Windows จะทราบว่านี้เป็น Manage code จาก file header ของ HelloWorld.exe ระบบปฏิบัติการ Windows จึง load CLR (Common language Run time) จาก file ที่ชื่อ MSCorEE.dll

ถ้าเป็นระบบปฏิบัติการ Windows 64 bit
MSCorEE.dll จะเก็บอยู่ 2 ที่คือ  %SystemRoot%\System32 (library 64 bit ของ ระบบปฏิบัติการ Windows) กับ %SystemRoot%\SysWOW64 (library 32 bit ของระบบปฏิบัติการ Windows)

ถ้าโปรแกรม Menanged code มี header เป็นแบบ 64 bit CLR จะโหลด MSCorEE.dll จาก directory %SystemRoot%\System32
ถ้าโปรแกรม Menanged code มี header เป็นแบบ 32 bit CLR จะโหลด MSCorEE.dll จาก directory %SystemRoot%\SysWOW64

ถ้าเป็นระบบปฏิบัติการ Windows 32 bit
จะไม่มี directory %SystemRoot%\SysWOW64 และ %SystemRoot%\System32 จะเป็น library 32 bit

สำหรับ %SystemRoot% ถ้าใครไม่ทราบจะหมายถึง directory ที่เก็บระบบปฏิบัติการ Windows ซึ่งส่วนใหญ่จะอยู่ที่ c:\Windows\System ยกเว้นว่าเวลาลงระบบปฏิบัติการจะเก็บไว้อีก directory อื่น

2) Step 2
เมื่อ CLR ถูก load ขึ้นมา CLR ก็จะตรวจสอบดูว่า Managed code ต้องการ .Net Framework version อะไรและทำการเปรียบเทียบ .Net Framework version ที่ได้ติดตั้งในเครื่อง ถ้าตรงกัน CLR ก็จะทำ step ถัดไปครับ

วิธีการตรวจสอบว่าที่เครื่องคอมพิวเตอร์มี .Net Framework version อะไรบ้างโดยดูจาก Registry

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP

ถ้าเครื่องคอมพิวเตอร์ไม่มี .Net Framework ที่ต้องการ CLR ก็จะ report error แล้วไม่ทำงานต่อ

3) Step 3
หลังจากนั้น CLR จะทำการ load Data type ชนิดต่างๆ ของตาราง 2 ตาราง ใน Metadata (ผมมั่นใจมากว่าผู้อ่านยังไม่ลืม ... ใช่ไหมครับ)

4) Step 4
หลังจากนั้น CLR จะทำการมองหาตำแหน่ง entry point (function Main) ภายใน IL code แล้วเริ่ม compile IL code ไปเป็นภาษา Native CPU

จาก code ตัวอย่าง บรรทัดที่ Console.WriteLine("Hello World"); CLR รู้ว่า Console เป็น function ที่อยู่ใน System ก็จะทำการอ่านรายละเอียด DataType จาก metadata จากนั้น CLR จะเรียก function JITCompiler (Just In Time Compiler) เพื่อทำการ compile Console.WriteLine("Hello World"); ไปเป็นภาษา Native CPU  แล้วนำ Native CPU code ไปเก็บไว้ในหน่วยความจำเพื่อส่งไปให้ CPU ประมวลผล

การ Compile IL code ไปเป็น Native CPU ระหว่าง execute โปรแกรมชนิด Managed Code เราเรียกสั้นๆ ว่า "runtime"

จากนั้น CLR จะมองไปที่บรรทัดถัดไป คือ  Console.WriteLine("Good Bye"); เนื่องจาก Console ถูก compile ไปเป็น Native CPU แล้วจากบรรทัดก่อนหน้า CLR ก็จะดึง Native CPU ที่ถูก compile เสร็จแล้วไปใช้ได้เลยไม่ต้องเสียเวลา compile Console อีกรอบ

แค่นี้เราก็จะได้ภาษา Native CPU ส่งไปให้ CPU ประมวลผลแล้วครับ

เมื่อเราออกจากโปรแกรม CLR จะคืน memory ที่เก็บ Native CPU กลับไปให้กับระบบปฏิบัติการ Windows แปลว่าสิ่งที่ compile มาตอน runtime ทั้งหมดก็จะหายไปครับ

คำถาม .... ถ้าผมมีการ execute โปรแกรม HelloWord.exe เป็นครั้งที่สอง CLR ยังจำเป็นต้อง compile IL code ไปเป็น Native CPU อีกไหม
คำตอบ .... จำเป็นครับ ทุกๆ ครั้งที่มีการ execute โปรแกรม Managed Code ตัว CLR จำเป็นต้อง อ่าน metadata อ่าน IL code และ compile IL code ไปเป็น Native CPU ทุกครั้ง แม้แต่การ execute โปรแกรม Managed Code ตัวเดียวกันพร้อมกัน ตัว CLR ก็จะ compile IL ไปเป็น Native code และเก็บไว้ในหน่วยความจำที่แยกกันครับ

เหมือนๆ CLR จะทำงานซ้ำซ้อน ไหมครับ ... ใช่ครับมันทำงานซำ้ซ้อนแต่มันจะทำเฉพาะตอนเปิดโปรแกรมครั้งแรกเท่านั้นในช่วงของ runtime ดังนั้นเพื่อเป็นการเพิ่มประสิทธิภาพของ Managed Code จึงเป็นสิ่งที่จำเป็นยิ่งที่จะต้อง optimize ทั้ง IL code และ Native CPU วิธีการ optimize คือ ....

พบกันใหม่บทความหน้าครับ
TuChay

วันจันทร์ที่ 3 สิงหาคม พ.ศ. 2558

Execute โปรแกรม Managed Code ตอนที่ 1


จากบทความที่แล้วผมได้อธิบายโครงสร้างของ file Manage code ว่ามีทั้ง 4 ส่วนและแต่ล่ะส่วนไม่ได้มีการเก็บ Native code ไปให้ CPU ประมวลผลเลย

การอธิบายที่ดีที่สุดคือการยกตัวอย่าง ตัวอย่าง code ข้างล่างเขียนขึ้นด้วยภาษา C# เป็นตัวอย่างง่ายๆ น่ะครับ

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World");
            Console.WriteLine("Good Bye");
        }
    }
}

เมื่อเรา coding เสร็จ เราก็จะทำการ compile code กัน ตัว C# compiler จะทำการสร้าง file มาให้ 2 file ที่มีนามสกุล .EXE และ นามสกุล .PDB โปรแกรมที่เราจะเอาไปใช้งานก็มีแค่ file นามสกุล .EXE

เนื่องจาก file .EXE เป็น Managed code เราจึงสามารถดูเนื้อหาภายใน file ได้ทาง Microsoft ได้ออก tool ที่ชื่อว่า CorFlags.exe เป็นโปรแกรมสำหรับเรียกดู header information ของ Managed code รูปแบบคำสั่งคือ

CorFlags <ManagedCode.exe>


จากตัวอย่าง code ข้างบน เราสามารถใช้คำสั่ง

CorFlags HelloWorld.exe


นี้เป็นตัวอย่างผลที่ได้จากคำสั่ง CorFlags.



จะเห็นว่า โปรแกรมนี้ต้องการ .Net Framework version 4.0 และต้องการ CLR version 2.5 CPU Header เป็นชนิด PE32 สำหรับ ILONLY จะหมายถึงเนื้อหาภายใน Managed code มีแต่เนื้อหา IL และไม่มี unsafe code

แต่ถ้าใครไม่สะดวกที่จะใช้ command mode ยังมี Tool อีก 1 ชนิดคือ CFF Explorer เป็น GUI application ที่ใช้สำหรับดู header ของ file Managed code.

Microsoft ยังมี tool อีกตัวที่ชื่อว่า ILDASM เอาไว้ดู IL code ของ Managed code ตัวอย่างคำสั่งน่ะครับ


ILDASM HelloWorld.exe


จะได้ดังรูปครับ



แต่ความสามารถ ILDASM ค่อนข้างจะมีจำกัดผมขอแนะนำโปรแกรมที่ชื่อว่า .Net Reflector โปรแกรมที่เอาไว้ดู IL code ที่ดีตัวหนึ่งเลยครับ ถ้าอยากให้ review โปรแกรม .Net Reflector ขอแค่บอกครับ เดียวจัดให้

อา .... ผมลืมบอกไปว่า Tools ของ Microsoft จะมาพร้อมกับ Visual Studio และจะต้อง รัน โปรแกรม command prompt ของ Visual Studio เท่านั้น น่ะครับ ถ้าใช้ command prompt ของ Windows เองจะใช้ได้ไม่ค่อยดีน่ะครับ วิธีเข้า command prompt ของ Visual Studio ดูได้ตามรูปเลยครับ



ตอนหน้าเจอกันแน่นอนครับ execute Managed code.
TuChay





วันอาทิตย์ที่ 2 สิงหาคม พ.ศ. 2558

PE32(+)


ในตอนที่แล้วผมค้างไว้ที่ เกิดอะไรขึ้นเมื่อ execute โปรแกรมชนิด Managed code ก่อนที่อธิบายถึงขั้นนี้ผมขออธิบายเกี่ยวกับ PE32(+) ก่อนน่ะครับ

จากที่ทราบกันว่าระบบปฏิบัติการ Windows ในปัจจุปันมีทั้ง 32 bit และ 64 bit หนึ่งในสิ่งที่ต่างกันระหว่าง version ทั้งสองคือ การส่งชุดคำสั่งไปให้ CPU ประมวลผล โดยระบบปฏิบัติการ 32 bit จะสามารถส่งชุดคำสั่งไปให้ CPU ประมวลผลครั้งล่ะ 32 bit สำหรับระบบปฏิบัติการ 64 bit ก็จะส่งชุดคำสั่งไปประมวลผมคั้งล่ะ 64 bit เพราะฉะนั้นระบบปฏิบัติการ 64 bit ก็จะสามารถทำงานได้รวดเร็วกว่า แน่นอนครับในปัจจุบันแทบจะไม่มี CPU ที่เป็น 32 bit ในท้องตลาด แต่ในระดับอุตสาหกรรม เช่น เครื่องจักรที่ใช้ในโรงงานซึ่งส่วนใหญ่จะใช้เป็น CPU customize การ customize CPU 64 bit ยังมีราคาที่แพงอยู่ รวมถึง hardware ส่วนอื่นๆ เช่น special card ที่ยังต้องติดต่อกับ CPU ที่ต้องต้องการติดต่อกับ CPU ระดับ 32 bit อยู่ ดังนั้นในปัจจุบันจึงยังมี CPU 32 bit และระบบปฏิบัติการ 32 bit ใช้อยู่นั้นเอง

สำหรับโปรแกรมที่เราพัฒนาขึ้นเราสามารถระบุชนิดของระบบปฏิบัติการ ที่เราต้องการให้โปรแกรมทำงานได้ การระบุชนิดของ ระบบปฏิบัติการ จะทำในกรณีที่มีการเขียน unsafe code หรือใส่ UnManged code ลงไปใน Managed code ในระบบปฏิบัติการ Windows XP ที่มีทั้ง 32 bit และ 64 bit จะไม่อนุญาติให้โปรแกรม execute ข้าม platform นักพัฒนาโปรแกรมจึงต้อง พัฒนาโปรแกรม 2 version สำหรับ Windows XP 32 bit และ 64 bit

แต่ในระบบปฏิบัติการรุ่นใหม่ Microsoft ได้ออก technology ที่ชื่อว่า WoW64 (for Windows on Windows 64) โดยจะอนุญาติให้โปรแกรมสำหรับ 32 bit สามารถ execute ได้บนระบบปฏิบัติการ 64 bit ด้วยการเลียนแบบโครงสร้าง ชุดคำสั่ง CPU 32 bit แล้วส่งไปให้ตัว CPU ประมวลผลในรูปแบบ 64 bit 

การ compile code โดยระบุชนิดของ CPU สามารถใช้ /platform เพื่อระบุชนิดของระบบปฏิบัติการ ตัวอย่างน่ะครับ


csc /platform:anycpu filename.cs
 

ถ้าเราเขียน code ด้วย Microsoft Visual Studio เราสามารถเลือกระบุชนิดของ CPU ได้ที่ property ของ Project ครับ




หลังจาก compiler compile code แล้ว compiler ก็จะสร้าง PE32(+) header ถ้าระบุเป็น 32 bit header ก็จะเป็นชนิด PE32 แต่ถ้าเป็น 64 bit header ก็จะเป็น PE32+ แต่ถ้าโปรแกรมสามารถ execute ได้ทั้ง 32 bit และ 64 bit header ก็จะเป็น PE32(+)

เมื่อเราทำการ execute โปรแกรมแบบ Managed code ตัว CLR (เป็นหนึ่งในชุดของ .Net framework) จะทำการดู header ของ โปรแกรมว่าต้องการ CPU แบบไหนแล้วเปรียบเทียบกับ CPU จริงๆ ที่อยู่ในเครื่อง computer เพื่อทำการ compile code IL ให้เป็น Native CPU ให้ตรงกับ CPU ของเครื่องจริงๆ ขั้นตอนนี้จะกล่าวอย่างละเอียดในบทความถัดไปครับ

Platform ที่เราสามารถเลือกใช่ในการ compile code มีดังนี้

1) anycpu 
     ตัวนี้จะเป็นตัว default ของการ compile code โดยจะระบุว่าโปแกรม สามารถ ทำงานได้ทั้ง 32 bit และ 64 bit ถ้า CPU ของเครื่องเป็น 64 bit ก็จะให้ CLR compile IL code ให้เป็น Native code แบบ 64 bit

2) anycpu32bitpreferred
    ตัวเลือกนี้ จะคล้ายๆ กับ anycpu แต่จะให้ CLR compile IL code ให้เป็น Native code ด้วยโครงสร้าง CPU 32 bit แม้โปรแกรมจะ execute อยู่บนระบบปฏิบัติการ Windows 64 bit ก็ตาม ความสามารถนี้จะใช้ได้ก็ต่อเมื่อ โปรแกรมรันบน .Net Framework version 4.5 ขึ้นไปเท่านั้น

3) ARM - Advanced RISC Machine
    ตัวนี้จะเป็นกรณี CPU ที่เป็น ARM ไม่ใช่ intel base ลักษณะของ CPU พวกนี้จะพบได้กับ smart phone หรือ PC ที่ต้องการกินไฟต่ำๆ เสถียรภาพสูงๆ ระบบปฏิบัติการส่วนใหญ่จะเป็น Windows Embedded เช่น Oscilloscope หรือ เครื่องมือทางการแพทย์ ณ ปัจจุบันรบบปฏิบัติการ Windows ทำงานบน ARM ตามท้องตลาดยังทำงานได้ไม่ดีน่ะ แต่ในอนาคต Microsoft ออกมาประกาศแล้วว่าระบบปฏิบัติการ Windows 10 จะสามารถรันได้บน Raspberry Pi 2 แบบ Free

    ผมปัจจุบันใช้ CPU ประเภทนี้อยู่เหมือนกัน ต้องยอมรับเลยครับว่าเหนื่อยถ้าจะเอา Windows มาลงบน ARM เพราะมีปัญหาทั้งเสถียรภาพ ความเร็วแล้วโดยเฉพาะ driver ถ้ามีโอกาสผมจะพาไปเจาะลึกอย่างละเอียดกับ CPU ประเภทนี้ (ในปัจจุบันผมใช้ CubieTruck with Ubuntu ใช้ USB power bank เป็นแหล่งจ่ายไฟ)

4) x64
   เป็นการบังคับใช้ CPU ชนิด 64 bit อย่างเดียวเท่านั้น ถ้ามีการ execute โปรแกรมที่ ระบบปฏิบัติการ 32 bit โปรแกรมจะแสดง error และไม่ทำงานต่อ ต่างจาก anycpu ที่โปรแกรมยังทำงานต่อไปได้

5) x32
   เหมือนกับ x64 แต่จะเป็นการบังคับใช้ CPU 32 bit เท่านั้น

6) Itanium
    CPU ชนิดนี้เป็น CPU เฉพาะ Windows server สำหรับ CPU ชนิด Itanium สำหรับ CPU ชนิดนี้ Microsoft ประกาศออกมาแล้วว่าจะไม่ support CPU ชนิดนี้อีกต่อไปโดย version Windows server 2008 จะเป็น version สุดท้ายของ CPU Itanium ครับ เอาเป็นว่าให้รู้ว่ามันมี CPU ชนิดนี้เคยยิ่งใหญ่อยู่บนโลกเราละกันครับ

บทความถัดไปผมจะอธิบายว่า Managed code ถูกแปลงเป็น Native CPU ได้ยังไง พบกันใหม่บทความหน้าครับ
TuChay