Friday, November 18, 2005

Re Party with Lisp

ช่วงนี้กำลังหัดเขียน common lisp อยู่
อ่าน post เรื่อง party ของ mk แล้ว
ก็เลยทดลองเขียน clisp ดูเล่นๆดีกว่า

เริ่มกันที่ funcation should-criticize?
ซึ่งเราจะใช้สั่ง run แบบนี้(should-criticize "ธีรยุทธ" "ทักษิณ")

(defun should-criticize? (a b)
(if (better? a b) t nil))

ความหมายก็คือ a มีคุณสมบัติพอที่จะวิจารณ์ b ได้หรือไม่
ก็ให้ call ไป function better? ถ้า return true
ก็จะ return t กลับไป ถ้าไม่ใช่ ก็จะ return nil (false ในความหมายของ lisp)

ลองนิยาม function better? ต่อ

(defun better (a b)
(if (> (how-good a) (how-good b)) t nil))

เขียนง่ายๆ ว่าถ้า a มีแต้ม how-good มากกว่า b
(how-good คือ function ที่ return คะแนนความดีกลับออกมา)
ก็ให้ return t (true)

ลองนิยาม function how-good
อืมม์อันนี้สิเริ่มยากแล้ว
เรารู้กันว่าความดีเป็น subjective แล้ว
a อาจจะดีกว่า b ในสายตา y
หรือ
b ดีกว่า a ในสายตา x
อย่างนี้ต้องย้อนกลับไป refactor code เดิม
ให้ส่ง c (คนที่มอง) มาด้วยดีกว่า
(งั้งเวลาสั่ง run ก็จะเป็นแบบนี้แทน (should-criticize "ธีรยุทธ" "ทักษิณ" "mk")))

(defun should-criticize? (a b c)
(if (better? a b c) t nil))

(defun better (a b c)
(if (> (how-good a c) (how-good b c)) t nil))


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

(setf *attrs* '("father" "business" "charisma" "pricky"))

(เอ้ คุณธีรยุทธ แกแต่งงานหรือยังหว่า?)

คราวนี้ต้อง loop ไปตาม list เพื่อเก็บคะแนนรวม
อืมม์ชักยากแล้วสิ ยังอ่านไม่ถึงบทที่ว่าเรื่อง iterator เลย

(defun how-good (subject object)
(let ((total 0))
(dolist (attr *attrs*)
(setf total (+ total (get-score subject object attr))))
total))

คนที่ไม่เคยใช้ lisp อาจจะร้องอุทานว่า "โอ อะไรกันนี้"
ส่วนผมที่พึ่งหัดใช้ ก็ยังร้องแบบเดียวกันอยู่
คำอธิบายก็คือ let เป็นการกำหนด scope ของตัวแปร
ในที่เราเขียนนี้ตัวแปร total จะมี life-cycle อยู่ใน ขอบเขตของ let เท่านั้น
ส่วน dolist เป็นการ loop ไปตาม list *attrs* ที่ให้มาโดย
ดึงค่าออกมาใส่ตัวแปร attr ทีละตัว
(setf x 1) มีความหมาย = int x = 1 ใน java
ส่วน get-score ก็คือ function ที่ return คะแนนที่ subject ให้กับ
object ในส่วนของคุณสมบัติต่างๆ
บรรทัดสุดท้ายก็คือการ return ค่า total กลับออกมา

อืมม์ดูแล้ว ลืมเรื่อง weight ไปเลย
เพราะแต่ละคนอาจจะให้นำ้หนักของ attributes ต่างๆไม่เท่ากันอีก
เปลี่ยนเป็นอย่างนี้ดีกว่า

(defun how-good (subject object)
(let ((total 0))
(dolist (attr *attrs*)
(setf total (+ total
(* (get-weight subject object attr)
(get-score subject object attr)))))
total))


เฮ้อ พอพอแค่ดีกว่า ไม่รู้จะ implement get-weight กับ get-score อย่างไงดี

Note:

CL-USER > (is-annoy-me "สนธิ")
T

แปลว่า ผมก็รำคาญสนธิเหมือนกัน
แต่ระหว่างทักษิณกับสนธิ, ผมรำคาญใครมากกว่ากันนั้น ไม่บอก

Related link from Roti

Wednesday, November 16, 2005

Cache with Ruby Hash

เวลาเราสร้าง Hash object ใน Ruby
เราสามารถ pass block เข้าไปได้ด้วย
ซึ่ง block นี้จะถูกเรียกใช้
เมื่อมีการ access hash ตาม key ที่ให้มา แล้วไม่พบค่าใน hash นั้น
ลองดู code
require 'pp'
h = Hash.new { |h, key|
h[key] = "result from #{key}"
}
puts h[1]
puts h[2]
pp h

ได้ผลลัพท์ดังนี้
result from 1
result from 2
{1=>"result from 1", 2=>"result from 2"}


Feature นี้ทำให้เราสามารถ implement cache ได้อย่างง่ายๆ
ลองดูตัวอย่างนี้
def fib(n)
return n if n < 2
fib(n-1) + fib(n-2)
end
puts fib(20)

เขียนแบบใช้ Hash จะได้ดังนี้

fib_h = Hash.new {|h, k|
if k < 2
h[k] = k
else
h[k] = h[k-1] +h[k-2]
end
}
puts fib_h[30]


ทดลองจับเวลา เปรียบเทียบการหาค่า n ที่เท่ากับ 30
ถ้าไม่มี cache จะใช้เวลา 4.3 วินาที
ส่วน version ที่ใช้ cache จะใช้เวลา 0.002 วินาที

ทีนี้ลองดู version พิสดารบ้าง
ไปเห็นมาจาก Concise Memoization
กับของ Cheap Ruby memoize using Hash default block

version พิสดาร จะใช้แบบนี้
สมมติเรามี method fib แบบ simple
def fib(n)
return n if n < 2
fib(n-1) + fib(n-2)
end

กรณีที่เราต้องการทำ cache method นี้
เราก็จะสั่งดังนี้
memoize(:fib)

โดย method memoize มีหน้าตาดังนี้
def memoize( name )
meth = method( name )
cache = Hash.new { |cache, args|
cache[args] = meth.call( *args )
}
( class << self ; self ; end ).class_eval do
define_method( name ) { |*args| cache[args] }
end
cache
end

จะเห็นมีว่าการนำ class_eval กับ define_method มาใช้
คนที่ยังไม่คุ้นกับ 2 method นี้ลองดูตัวอย่างนี้
class X
def hi
puts 'Hello'
end
end

X.new.hi # output -> Hello

X.class_eval do
define_method(:hi) { |*args|
puts 'hi pok'
}
end

X.new.hi # output -> hi pok

Related link from Roti

Tuesday, November 15, 2005

Mouseover DOM Inspector

MODI เป็น Bookmarklet ที่ทำให้เรา inspect DOM element บน page ได้

Related link from Roti

Cross Browser Screenshots

browsershots มีบริการทดสอบเปรียบเทียบ Page ของเราว่าจะมีหน้าตา
อย่างไร เมื่อ browse ด้วย browser ต่างๆ
browser ที่มีบริการ ประกอบด้วย
  • MSIE 6.0
  • Epiphany 1.4.8
  • Firefox 1.0.4
  • Galeon 1.3.20
  • Konqueror 3.3
  • Mozilla 1.7.8
  • Opera 8.50
  • Safari 2.0

เวลา post ไปแล้ว จะยังไม่ได้ผลลัพท์ทันที
เขาจะ queue request เราไว้ก่อน

ลองดูตัวอย่างผลลัพท์ที่ได้ Results

เท่าที่ลองดูปรากฎว่าช่วงนี้ queue เต็ม

น่าสนใจว่า เขา implement program กันอย่างไง

Related link from Roti

SPECjAppServer2004

วันนี้อ่านเจอ Thread ใน TSS
ที่ว่า Websphere ทำคะแนน SPECjAppServer2004
ได้ 2921.48 แต้ม
เทียบกับ Sun/BEA/Oracle ที่ post คะแนนไว้ที่ 1781.47

ในส่วนของ App Server Hardware
SUN/BEA/Oracle ใช้ Sun Fire X4100
processor AMD Opteron 280 (dual core)
จำนวน 5 เครื่อง เครื่องละ 2 cpu
memory เครื่องละ 4 GB
เทียบกับ IBM ที่ใช้ P5 550
processor POWER5+(dual core)
จำนวน 8 เครื่อง เครื่องละ 2 cup
memory เครื่องละ 4 GB

น่าสนใจที่เครื่องของทั้ง IBM และ Sun
อยู่ในกลุ่ม entry-level server ทั้งคู่

Hardware ที่น่าสนใจอีกตัวก็คือ
Database Server
ทาง Sun ใช้ Sun Fire E6900
cpu UltraSPARC IV (dual core)
ใส่ไปแค่ 16 ตัว
ส่วน Ram อัดไปแค่ 64 GB
ส่วนทางฝั่ง IBM
ใช้ IBM eServer p5 570
cpu POWER5 ทั้งหมด 4 ตัว
ส่วน Ram ใช้เท่ากันคือ 64 GB

db server ที่ทั้งคู่ใช้ จัดอยู่ในกลุ่ม Mid-range เหมือนกัน

ประเด็นที่สงสัยก็คือ ทำไมทางฝั่ง sun มันใช้ cpu บน DB Server
เยอะขนาดนั้น อยากรู้ % cpu ว่ามันกินไปเท่าไร ระหว่างที่ run beachmark
(ข้อเสียของ spec พวกนี้ก็คือ เห็นแต่ตัวเลขสรุป
ไม่เห็น graph หรือข้อมูลอื่นๆเลย)

ที่น่าสนใจตรง post จาก BEA ที่มีข้อมูลราคาให้ดูด้วย
IBM/WAS/DB2 publish:
AppServer Hardware: $192,000
AppServer Software: $480,000
Database Hardware: $377,000
Database Software: $181,000
Total = $1,230,000
Total $/JOPS = $1,230,000/2921 JOPS = $421/JOP

SUN/BEA/Oracle publish:
AppServer Hardware: $38,000
AppServer Software: $100,000
Database Hardware: $752,000
Database Software: $566,000
Total = $1,456,000
Total $/JOPS = $1,456,000/1781JOPS = $817/JOP


Steve Realmuto จาก BEA
post ใน Thread ต่อด้วยว่า

That said, the total SPECjAppServer2004 JOPS number for any result is also dependent on the underlying hardware, so you need to look this number in the context of the hardware required to achieve it. The design of this benchmark is such that the application server tier is infinitely scalable. Essentially, you can achieve any desired result by throwing enough hardware at it.

Another way to normalize results across different hardware platforms is to look at the number of application server CPU cores required to achieve a given result. For example, how many CPUs per 1000 JOPS were used. This method is far from perfect, but it can provide some useful insights. IBM's latest result achieved 2921.48 JOPS@Standard using 32 Power5 application server CPU cores or 10.95 CPUs per 1000 JOPs. The previous high result from IBM achieved 1343.47 JOPS@Standard using 20 Intel Xeon application server CPU cores or 14.89 CPUs per 1000 JOPS. For comparison, BEA's WebLogic Server achieved 1664.36 JOPS@Standard using 12 Intel Xeon application server CPU cores or 7.21 CPUs per 1000 JOPS.


Note: post นี้ไม่มีข้อสรุป ฟังหูไว้หู

Related link from Roti

Sunday, November 13, 2005

Trip พายเรือ #1

ได้เล่น google earth แล้วรู้สึกชอบใจ
ก็เลยขอบันทึกเส้นทางการเดินทาง ที่เคยพายเรือ
จากเชียงใหม่ลงมากรุงเทพฯ เมื่อ 8 ปีก่อน

เริ่มเดินทาง 12/12/2540 เวลาบ่าย
โดยใช้เรือ canoe เป็นพาหนะ
ใช้พายแบบพายเดี่ยว
เรือนี้ยืมมาจากเรือโรงแรมที่ให้บริการที่เขื่อนภูมิพล



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

ระหว่างทางมีฝายกั้นน้ำ 3 แห่ง



การนำเรือผ่านฝาย ต้องใช้วิธีขนของทั้งหมดลงจากเรือ
แล้วก็ปล่อยให้เรือลอยลงไปเอง
(เรือมันจะเบา ทำให้ไม่พุ่งชนก้อนหิน)
จริงๆแล้ว มันก็ดูเหมือนพอจะพายลงมาได้เหมือนกัน
แต่ไม่อยากเสี่ยง เรือแตก จบ trip ตั้งแต่วันแรก

การผ่านฝายแต่ละฝายจะใช้เวลาค่อนข้างมาก
เพราะต้องขนของลงเรือ แบกของไปอีกฝั่ง
ปล่อยเรือ ขนของขึ้นเรือ
เหนื่อยสุดๆ

ทิวทัศน์ 2 ข้างทางในช่วงนี้
ประกอบด้วยบ้านผู้มีอันจะกินทั้งสิ้น
(ประชันความหรู ตลอดทาง)

จำได้ว่า รู้สึกตื่นเต้นมากเมื่อถึงตอนเย็น
รีบถามชาวบ้านใหญ่เลยว่า
ตอนนี้อยู่ห่างจากเชียงใหม่มากไหม
ชาวบ้านก็ทำหน้างงๆ
บอกว่า ประมาณ 10 โล
ไอ้เราก็นึกว่า ป่านนี้คงมาได้ไกลโขแล้ว

หลังจากมี google earth
แล้วจึงรู้ว่าระยะทางที่พายได้ 7 โลนิดๆ

หมู่บ้านที่ขออาศัยพื้นที่พักนอน
เป็นหมู่บ้านของพวกคริสต์
สถาปัตยกรรมน่าสนใจทีเดียว
การขอนอน ต้องซ้อนท้ายมอเตอร์ไซด์
ไปหาผู้ใหญ่บ้าน เพื่อขออนุญาติพักนอน

ค้างคืนวันแรกโดยใช้เปลผูกต้นไม้ริ่มฝั่ง
ปีนั้นเป็นปีที่อากาศไม่หนาว
ทำให้ยุงเยอะมาก
ตื่นขึ้นมา ท้ายทอยส่วนที่สัมผัสเปล
มีอาการบวมตุยเชียว
(ยุงมันเล่นกัดรอดผ้าเลย)

อุปสรรคที่หนักสุดสำหรับวันแรก
ก็คือ ความกลัว
กลางวันไม่มีอะไรอยู่แล้ว
แต่กลางคืนนี่สิ
น่ากลัวมาก
(แต่หลังจากผ่านไปได้ 8 วัน
ไม่มีผีโผล่มาหลอกสักครั้ง
ก็เลยหายกลัวโดยสิ้นเชิง)

Related link from Roti