Tuesday, February 01, 2005

Assembling a home theatre PC

I've wanted to build an AMD-64 for some time and I finally got started with the following parts. All items were located on Pricewatch. For some items, I did not automatically choose the cheapest vendor if the vendor had less than best ratings.

The general plan is to have a media box such as this.

ItemPrice (w/. shipping)QtyAmount
AMD Athlon 64 939 3500+ $262.701$262.70
Asus A8N SLI skt939$194.001 $194.00
Ahanix D4 $229.58 1 $229.58
Zalman CNPS7000B-CU Cooler $52.00 1 $52.00
Samsung PC3200 512MB $82.00 2 $164.00
HITACHI 250GB SATA $120.00 2 $240.00
Hauppage WinPVR-250 $128.00 1 $128.00
PCI express eVGA 6600 256MB $129.00 1 $129.00
Arctic Silver 5$6.00 1 $6.00

In addition, I bought some Everclear 95% grain alcohol from a liquor store for cleaning the computer parts. (Never use anything other than pure grain alcohol!)

In general, stores where shipping is free tend to ship via snail mail, so when looking at the price, factor that in.

Most items were packed perfectly. I was impressed with the packing of the hard drives and the Ahanix case. Other items were packaged adequately. The only exception was the Zalman cooler, which had some copper cooling blades bent because they did not seal the box. Copper is a soft metal and bends easily. the fan also looked very slightly scuffed. I straightened out the fins of the Zalman carefully. Then I verified that the fan ran silently and decided not to ask for an exchange.

First impressions:

The Ahanix D4 case looks like a stereo component device. The front metal face is about a quarter inch thick and feels luxurious. A hinged door that covers the 5.25 inch bays is held together by magnets and impresses quality. The entire case is aluminum and is very well constructed. The included power supply is silent and the case is designed to be kept cool. I wont review the case fully here since its been reviewed elsewhere, but suffice to say this is the best case you can get that holds a full ATX board and worth every penny. The D5 is cooler looking, but does not seem to have front USB/firewire ports and has an infra-red remote control sensor that is plugged to the USB port. I was not sure how it would work with lirc, so I did not buy it. The only negetive about this box is that smudges can be easily seen when you touch it.

The AMD Athlon 64 CPU looked like it had some extremely thin layer of gunk on it (returned item?) but I washed it with alcohol and it evaporated.

The Zalman CNPS7700-Cu cooler is a thing of beauty. It looks like a copper flower. The fan is large and silent. It comes with a fan control device, some thermal grease and various brackets. I cleaned its bottom with alcohol too.

The Asus A8N SLI deluxe motherboard truly deserves the Deluxe tag. It comes with every imaginable cable and fixture including a SATA fixture that allows you to plug in SATA drives at the back. The chipset fan is reasonably silent. The optical SPDIF out makes this board attractive to Home Theater projects. The 8 SATA RAID interfaces don't hurt either. The most important feature however, is Nvidia chipset, which has good Linux support from the vendor.

The Arctic silver 5 compound comes in a tiny syringe with a rubber dome top.

The Hitachi SATA hard drives run great, but are not as silent as their IBM counterparts (before IBM sold their hard drive division to Hitachi). It could be because I have 2 SATA drives in raid config (more on that later) and they make the seek sound simultaneously. I need to investigate into silencing the drives a bit more.

The eVGA GeForce 6600 with 256MB seems to be the fastest card at the price. This card comes with a shrouded fan. If you are a serious gamer (I'm not), its a good idea to go with the 6800 GT and get the Arctic cooler for it.

The RAM looked like ... RAM. The DIMMS had Copper heat spreaders on them and the word RAMSES printed. I complained to the vendor that he had sent me Ramses brand when I had requested Micron. He told me that the heat spreader was Ramses and the RAM was actually Samsung, which was allegedly better than Micron. I decided to keep the RAM if it ran stable. Fortunately, it did.

I had an old Plextor 712A DVD Writer, which I plugged into the system.

Hardware installation:

First, I removed the motherboard backplate provided by Ahanix. The items simply did not match my motherboard. I replaced it with one included by ASUS. The motherboard comes with a bracket and baseplate for the stock CPU cooler which I removed and then attached the baseplate that came with the Zalman cooler (using the nipples provided). I placed the motherboard on a flat surface and lifted the ZIF socket's lever and then aligned the CPU's golden triangle with the triangular mark on the ZIF socket. It fell into place easily. Placing the CPU on the ZIF socket and pushing the lever back to horizontal position is about the easiest thing to do.

Next, I took the Arctic silver 5 syringe and punctured the top with a pin and then squeezed about 1 and a half rice grain lengths on the CPU. I then gently lowered the Zalman cooler and aligned the screw holes with the nipples. Once the cooler sits on the CPU, a suction prevents you from easily picking up the cooler. but you can turn it slightly. I then screwed in the cooler tight alternating each screw.

I then lifted the motherboard with the CPU and cooler into the case and screwed it to the base. (Some folks prefer to attach the board first and then install the CPU and heatsink, but given that Arctic silver is slightly capacitative, I needed to be absolutely sure that not a single particle would fall onto the motherboard.)

Next, I installed the Samsung 512MBx2 PC3200 RAM which had copper heat spreaders on them into the appropriate banks (A1 and B1) to make best use of DDR feature.

Next, I installed the Hitachi SATA hard drives. You only get access to one side of the bay, so I screwed them in.

Next, I installed the PCI-Express eVGA card into the blue PCIe slot (as recommended if using a single slot)

Last, I connected all the case connections such as the power and hard drive LEDs

Linux Installation: Most folks would do well to just install the KnoppMyth distribution, but I'm a gentoo fanatic, so I downloaded the AMD64 ISO and installed gentoo and installed from stage3. Standard procedure with some hints for raid.

The only things I need to tell you are: For the sound card, I chose snd-intel8x0 (alsa driver) and for the net I chose forcedeth. Although I got nvidia's nvsound and nvnet to work after applying patches, I saw no advantage over standard kernel provided drivers. For the video, I emerge nvidia-kernel and added nvidia to modules.autoload. I managed to setup SPDIF using instructions here. I see that my SPDIF is properly setup:

# cat /proc/asound/pcm
00-00: Intel ICH : NVidia CK804 : playback 1 : capture 1
00-01: Intel ICH - MIC ADC : NVidia CK804 - MIC ADC : capture 1
00-02: Intel ICH - IEC958 : NVidia CK804 - IEC958 : playback 1
So I should be able to play it like this:
# mplayer -ao alsa:device=hw=0.2 mozart.mp3
But either my receiver has no support for it or I need to do something like this or this. So I went back to analog sound output.

The video was tricky. I finally managed to get the right xorg.conf file but I had two serious problems. The first, the cursor was a transparent square area with a cluster of black dots and second, the icons and text would disappear if the mouse went over them (or sometimes just by themselves). Fortunately, I found a patch on the internet for xorg and recompiled with it. All I did was emerge it, when it said 'Source unpacked' I pressed control+Z, applied the patch and resumed the job. I really should do something like this (go to bottom), but I'm guessing that they will have the bugfix in the next version anyway.

Its important to autoload the nvidia module or you get a "failure to load nvidia" error when you start X.

I struggled to setup the RAID, until I realized that the onboard RAID controllers are nothing more than a place in the BIOS to store your settings. Linux still sees the physical hard drives. Grub probes the BIOS, so it sees the real drives. You cannot install GRUB with fakeraid. The best option was to use mdadm and Linux software raid, which is just as fast if not faster. The utility mdadm was part of the installation cd, so I used it to setup the raid. The trick of course, is to set your boot partition as RAID-1, so that grub will load off it. Install grub in both partitions as shown here. I could probably have used the hardware using instructions here.

I got the Vacuum Fluorescent Display (part of the D4 case) working using these instructions. The VFD displays y with umlaut when the it tries to display a filled square for which I found a patch here

Wealth of info here

Noise

In general, I can constantly hear the constant whoosh of the fans at the back (I've disconnected one). The motherboard chip fan was the noisiest and I noticed that it was running at 8000+ RPM. I fixed the fan speed regulator that came with the CPU cooler and attached it to the motherboard chip fan and turned it fully down. The fan now runs at 4000+ RPM, but has almost negligible sound. The hard disks are silent unless there is activity, which I figure is the sound echoing off the case. The activity is occaisional even when compiling the kernel due to the 8MB caches.

Infrared

I purchased the parts off Radio Shack and soldered my own infra red receiver. I attached the IR sensor off a long wire, so I could squeeze it into the space provided by the D4 case (just above the HDD light left of the VFD).

Heat

In general, the CPU runs at 35C with the case open and 43C with the case closed at idle. On heavy load, it goes upto 55C. The motherboard temp and the case ambient temperature is generally about 5C and 15C below the CPU temperature.

Conclusion

All in all, I'm happy with the power and performance of this machine. I aim to install the arctic cooler for my VGA card and I also need to figure out how to reduce the noise of the fans and the hard disks.

Monday, January 24, 2005

Historical: Typewriter

When I was a kid, I wrote this assembly program that would play with the VGA fonts (I wrote a whole bunch of programs that messed with the VGA fonts) One particular program that comes to mind is one that shifts the lines on the VGA font one scan line upward, making it look like it was typed on a typewriter with an errant key.


SCANLINES	equ	16
SHIFT		equ	 2

.model small
.code
	org	100h
main	proc
	mov	ax,1130h	; read char vector
	mov	bh,06		; 8*16 vga/mcga
	int	10h

	mov	ah,0		; read char
	int	16h
	cbw
	push	ax
	
		
	mov	cl,4		; map of offending char
	shl	ax,cl
	add	bp,ax
	add	bp,SHIFT	
	
	mov	cx,SCANLINES-SHIFT	; save char bitmap
	push	ds
	push	es		
	pop	ds
	pop	es
	mov	si,bp		; ds:si->original map
	lea	di,charmap	; es:di->our buf
	cld
	rep	movsb	
			
	mov	ax,1100h	; set char
	mov	cx,1
	pop	dx
	mov	bh,10h		; 8*16 vga/mcga
	lea	bp,charmap
	int	10h

	mov	ax,4c00h
	int	21h
main	endp

charmap	db SCANLINES dup(0)	; init to 0 as last lines must be blank
	end	main

History: Executing a program in DOS

A common trick in the old days was to execute an application from within another. Here is some code example of how that was normally done:

.model tiny
.code

ExecBlk	Struc
	Psp	dw	?
	Cmdline	dw	?
	CmdSeg	dw	?
	FCB1	dw	?
	FCB1seg	dw	?
	FCB2	dw	?
	FCB2seg	dw	?
ExecBlk	ends

	org	100h

main	proc
	lea	bx,pspblk
	mov	sp,bx
	call	resize	

	mov	execb.psp,0		; copy our environment
	mov	execb.cmdline,80h	; pass command line as is
	mov	execb.FCB1,5ch
	mov	execb.FCB2,6ch
	mov	execb.cmdseg,cs
	mov	execb.FCB1seg,cs
	mov	execb.FCB2seg,cs
	lea	dx,execf
	push	ds
	pop	es
	lea	bx,execb
	mov	ax,4b00h
	int	21h
merr:
	mov	ax,4c00h
	int	21h
main	endp

resize	proc
	add	bx,15
	mov	cl,4
	shr	bx,cl
	mov	ax,cs
	add	bx,ax
	mov	ah,4ah
	int	21h
	jc	merr
	ret
resize	endp


execf	db	"PAT.COM",0		; ASCIIZ pathname of file to be execd
execb	ExecBlk	<>
_stack	dw	1000h dup(?)

pspblk	label	byte

	end	main

Friday, December 31, 2004

Is BASIC good for anything?

Has BASIC become the red haired stepchild that nobody wants?

Some folks look down upon BASIC programmers; in fact they even avoid thier company. I'm not trying to say that all programmers are equal in the eyes of the CPU or anything, but remember that Bill Gates is basically a BASIC programmer and that BASIC was once the language of choice for many music related application in the 80's. BASIC's PLAY keyword makes it simple to program musical notes and I'm sure the language has a couple of other redeeming features as well (I just can't remember what they are at the moment).

BASIC's lack of the need for formal structure such as class declarations or include statements plus its interpreted nature makes it a popular language to learn programming even in places like India where everyone is allegedly born partially a programmer.

Speaking of India, here is a song written entirely in BASIC.

10 '+------------------------------------------------------------------------+
20 '|                      The Indian National Anthem                        |
90 '+------------------------------------------------------------------------+
110  PLAY "L8C#D#FFFFFFL4FL8FFD#FL4F#"  '| Jana gana mana adhinayaka jaya hai|
120  PLAY "L4FL8FFL4D#L8D#D#CD#L2C#"    '| Bharatha bhagya vidhatha          |
130  PLAY "L4D#G#L8G#L4G#L5G#"          '| Punjaba Sinda                     |
140  PLAY "L8G#L4G#L8G#G#G#L8A#L4G#"    '| Gujaratha maratha                 |
150  PLAY "L4F#L8F#F#L4FL8FFD#F#L1F"    '| Dravida uthkala vanga             |
160  PLAY "L4FL8FFl4Fl8fd#g#g#l4g#f#f#" '| Vindhya Himachala Yamuna Ganga    |
170  PLAY "L4fl8ffd#d#d#l8cl4d#l1c#"    '| Uthkala jaladi taranga            |
180  PLAY "L8ffffl4fl4fl8d#fl1f#"       '| Tava shubha name jage             |
190  PLAY "L8ff#g#g#l4g#l8f#fd#l8f#l1f" '| Tava shubha ashisa mage           |
200  PLAY "l4ffl8d#d#d#d#cd#l1c#"       '| Gahe Tava jaya gatha              |
210  PLAY "l8g#g#g#g#l4g#l8g#g#"        '| Jana gana mangala                 |
220  PLAY "l4g#l8g#g#g#l8a#l4g#"        '| Dayaka jaya hai                   |
230  PLAY "l4f#l8f#f#l4fl8ffl8d#f#l1f"  '| Bharatha bhagya vidhata           |
240  PLAY "o5l8ccl1c#l8co4a#l1o5c"      '| Jaya hai jaya hai                 |
250  PLAY "l8o4g#g#o5l1o4a#"            '| Jaya hai                          |
260  PLAY "l8c#d#fff#f#d#fl1f#"         '| Jaya jaya jaya jaya hai           |
270  END                                '+-----------------------------------+

Choosing the best suited language

But its got to be done in Jaavaa! (or .NET or VB or whatever)

No, Dr. Dre, you need to choose what's the most suitable language to solve the problem. Believe it or not, the complexity of the application changes dramatically with a language that thinks differently from the problem class at hand.

For example, consider a simple app that converts strips non-ASCII characters by converting them to their ASCII counterparts.

Lets say your manager loves BASIC and writes it as below


OPEN "unstripped" FOR INPUT AS #1
OPEN "stripped" FOR OUTPUT AS #2
WHILE NOT EOF(1)
     a$ = INPUT$(1, 1)
     n = ASC(a$)
     IF n > 127 THEN
           PRINT #2, CHR$(ASC(a$) - 128);
     ELSE
           PRINT #2, a$;
     END IF
WEND
CLOSE
END
That is quite reasonable, isn't it? You could probably write something equivalent in C, Java or related languages.
Yes, but look how much simpler it would be if Perl was chosen as the language of choice.

perl -pe 'y/\x80-\xff/\x00-\x7f/'
Its a one liner you type on the command line. For text processing, Perl tends to beat any other language.

Tuesday, December 07, 2004

Writing good hashcodes and equals

How would one write a good hashcode? Here is one I've seen in real life:

class Thing
{
    List itemlist;

    public int hashCode()
    {
        return toString().hashCode();
    }

    public boolean equals(Object o)
    {
        return o.toString().equals(toString());
    }

    public String toString()
    {
        return "Items = " + itemlist.toString() ;
    }
}
For reasons of brevity, I've drastically reduced the size of the original toString() function, but suffice to say, it printed the all elements of the entire complex Object with appropriate keywords. And the member itemlist was one that could grow indefinitely long. It was obvious that the dude who wrote it does not know what a hashcode is at all. A hashcode serves as a value for quick comparison between Objects. It is essentially used to quickly locate which bucket the item is stored in HashMaps and other data structures that provide near constant access time. If the hashCode computation takes longer than the equals comparison, then you need to brush up on your fundamentals. What could be done differently? A simple way to define a good hashCode is given below:
class A
{
    Integer a, b;
    String c;
    Set d;

    public int hashCode()
    {
        // Sum of (prime number * hashcode) for selected members
        return 7 * a.hashCode() + 11 * b.hashCode();
    }

    public boolean equals(Object o)
    {
        if(o == null || !getClass().equals(o.getClass()) || o.hashCode() != hashCode())
            return false;
        A other = (A)o;
        return other.a == a && other.b == b
            && c.equals(other.c) && d.equals(other.d);
    }
}
As you can see, while equal Objects imply equal hashCodes, the converse is not necessarily true. Most of the time, the check for class and hashCode will eliminate most matches. Among the few that do match, you just need to compare the itemlists without converting them to String first. This has the added benefit that the comparison can terminate early for example if the lengths are different. If you do not have any other members or you believe that they do not sufficiently provide a proper distribution of the hashcodes, you can define the functions as below:
class Thing
{
  private List itemlist;

    public int hashCode()
    {
        if( itemlist != null && itemlist.size() > 0 )
            return itemlist.size() * 7 + itemlist.get(0).hashCode();
        else
            return 0;
    }

    public boolean equals(Object o)
    {
        if (o == null || !getClass().equals(o.getClass()) || o.hashCode() != hashCode())
            return false;
        Thing thing = (Thing)o;
        return thing.itemlist == null && itemlist == null ||
            thing.itemlist.equals(itemlist);
    }

    public String toString()
    {
        return "Items = " + itemlist.toString() ;
    }
}
Of course, you have to ask yourself what business you have in returning toString() of classes that can be very large. If unavoidable, you should at least cache the results of toString() and hashCode() and update them on changes. This may need synchronization, so generally keeping hashcodes and toString functions simple is the better choice.

Thursday, September 16, 2004

Does Java pass Objects by reference?

You often hear that Java passes primitives by value and Objects by reference. Unfortunately, this is misleading. A reference has a specific meaning in programming terminology. A reference is the variable itself. Its not a pointer, its not a copy, its the actual variable. This means that if a variable is passed by reference to a function and the function assigns another value to it, the changes are visible outside the function. C++ implements references faithful to the original meaning while Java does not.
#include <iostream.h>

class Ref
{
        public:
        int one(int& it) { it = 1; } // Reassign variable
        void two(int& it) { it++; }  // Change variable
};

int main()
{
        Ref ref;

        int item = 0;
        ref.one(item);
        cout << "Item is " << item << endl;
        ref.two(item);
        cout << "Item is " << item << endl;

        int* i = new int(0);
        ref.one(*i);
        cout << "I is " << *i << endl;
}
Prints:
Item is 1
Item is 2
I is 1
Java on the other hand, passes a copy of the reference. This means that any changes to the variable are preserved, but you cannot reassign the variable to point to something else within the traditional meaning of "reference."
import java.util.Date;

public class Ref
{
        public void one(Date item) { item = new Date(); }

        public void two(Date item) { item.setTime(365*24*60*60*1000L); }

        public static void main(String[] args)
        {
                Date item = new Date();
                item.setTime(0);
                Ref ref = new Ref();
                ref.one(item); // Change not reflected here
                System.out.println("Item is "+item);
                ref.two(item); // Change is reflected here
                System.out.println("Item is "+item);
        }
}
Prints:
Item is Wed Dec 31 19:00:00 EST 1969
Item is Thu Dec 31 19:00:00 EST 1970
The net effect of this is that a Java function can change the Object passed to it, but any reassignment to something else is lost. Many argue that this is indeed safer and C++ funtionality can be achieved by having the function return the new value and let the caller assign it to the actual variable. It also protects the programmer from having to overload the = operator when calling outside code to ensure that the reference is not reassigned. Click here for good reference on References