Thursday, December 1, 2011

Optimize fonts and memory on Solaris 11 desktop

Solaris 11 was released on Nov. 9th, 2011, this is the result of 7 years of huge engineering efforts since Solaris 10. Although Solaris is mainly designed for servers nowadays, Solaris is also good for desktop usage: ZFS, timeslider, DTrace, etc. Solaris 11 comes with GNOME 2.30 which is a very stable version (I'm disappointed with GNOME 3 shell or Ubuntu Unity) and Nimbus theme (created by Sun) which is my favorite theme.
I made some changes to the default settings of Solaris 11 desktop to suit my needs. 

Fonts
The most important part for the user experience on the desktop might be fonts. Different people have difference preferences on fonts and the same font has different effects on various font-size and screen resolutions, therefore I need take some time to test different fonts and find the appropriate ones for my desktop. In the end, I chose the following fonts for my desktop screen (20.1", 1600x1200 LCD): "Nimbus Sans" for English font,  "WenQuanYi Micro Hei" for Chinese font. Below are the steps for setup:
Change  Desktop Appearance
Right click the desktop -> Desktop Appearance... -> Fonts, set the Application, Document, Desktop, Window title font to "Nimbus Sans", size "10" and set the Fixed width font to "Liberation Mono".  (Note: do not use Chinese fonts in Desktop Appearance, because some Chinese fonts at some sizes make "i" looks "l")
Install Chinese fonts.
Solaris 11's default Chinese font is "AR PL ShanHeiSun Uni" (文鼎PL細上海宋Uni),  which is a free, long history, high-quality font on Unix/Linux. But I want to use a more modern font.  Solaris 11 software repository include "WenQuanYi Zen Hei" font ( To view which fonts are available, open Package Manager -> System -> Fonts) , but I personally feel it does not fit my screen.  "WenQuanYi Micro Hei" is a better option.To install it:
  1. Download from here 
  2. Unpack the downloaded file
  3. mkdir -p ~/.fonts
  4. Copy the "wqy-microhei.ttc" file to ~/.fonts
  5. (optional) Run "fc-cache" in terminal.
  6. To verify: run "fc-list | grep WenQuanYi", you should see that.
Change the system fonts configuration
The "Sans-serif", "Serif" and "Monospace" fonts are mapped to the default system fonts in /etc/fonts, to customize it, I did:
  1. mkdir -p ~/.fonts.conf.d/
  2. cp /etc/fonts/conf.d/60-latin.conf ~/.fonts.conf.d/
  3. cp /etc/fonts/conf.d/65-nonlatin.conf ~/.fonts.conf.d/
  4. edit ~/.fonts.conf.d/60-latin.conf
    move Nimbus fonts to the front in each section so that "serif" maps to "Nimbus Roman No9 L", "sans-serif" maps to "Nimbus Sans L", and "monospace" maps to "Liberation Mono".
  5. edit ~/.fonts.conf.d/65-nonlatin.conf
    add "WenQuanYi Micro Hei" before "WenQuanYi Zen Hei" for both "serif" and "sans-serif",  and add "WenQuanYi Micro Hei Mono" before "AR PL ShanHeiSun Uni" for "monospace".
  6. To verify: run "fc-match sans", "fc-match monospace" and "fc-match serif" in terminal.

Memory
My x86 workstation has very limited memory, so I need to make changes to limit the unnecessary memory use. Here are options that you can do to save the memory:
  • Desktop Appearance -> Visual Effects, choose "None"
  • System -> Preferences -> File Management, disable "Preview"
  • System -> Preferences -> File Indexing, disable "indexing"
  • System -> Preferences -> Startup Applications, disable anything you don't want
  • Only keep the necessary Applets on your task bar
  • Check your and root cron jobs (sudo crontab -l), disable unnecessary jobs with "crontab -e"
  • Check the SMF services using "svcs" command, disable unnecessary services with "svcadm disable" command



Wednesday, November 16, 2011

Cloud Foundry

A little background
Cloud Foundry project is an open-source platform-as-a-service (PaaS) project initiated by VMware. CloudFoundry.com is a VMware hosted, managed and supported PaaS environment. Micro Cloud Foundry is a complete version of Cloud Foundry that runs in a virtual machine on a developer’s Mac or PC.

Try Cloud Foundry
There are 2 ways: install it from github or use Micro Cloud Foundry virtual machine image provided by cloudfoudry.com. The second method is relatively simple and requires an CloudFoundry.com account. Because I already have an account, I used the second method.
The testing was not very smooth by following Micro Cloud Foundry Quick Start guide. The major problem was the network issue: the VM image uses the bridged network, however, in my env, it bound to the wrong network physical adapter (you should be careful about this especially when you have multiple network adapters or you have Virtualbox installed). The cloud foundry setup didn't pointed out this problem. This caused me to use vcap.me as the domain.
To fix above issue, I need use the virtual network editor to change the binding from automatic to a dedicated network adapter. The VMware player doesn't install the virtual network editor by default, I had to follow this guide to manually extract the installation file (VMware-player-xxxx.exe /e folder-name) , find the network.cab and extract the vmnetcfg.exe and copy it to VMWare Player folder. (C:\Program Files (x86)\VMware\VMware Player).
Another issue is VCAP ROUTER: 404: after setting up the micro cloud, vmc command failed with below message: Error (JSON 404): VCAP ROUTER: 404 - DESTINATION NOT FOUND I tried reconfiguring the domain in micro cloud setup menu, the problem was gone.

Thoughts
As for cloud computing, provisioning VM instances or application instances is relatively easy, the resource management is a challenge.

Friday, October 28, 2011

Build FBReader on Solaris

Here are my steps.
Environment: 
Solaris 11 Express x64
Gnome desktop
gcc-3.4.3
PATH=/usr/sfw/bin:/usr/gnu/bin:/usr/bin:/bin

Step 1: Build the dependencies first
$./configure; make; sudo make install
These libraries will be installed in /usr/local/lib

Step 2: Build FBReader-0.12.10
Need some hacks here.
1) makefiles/arch/desktop.mk
     13 CFLAGS = -pipe -fno-exceptions -Wall -Wno-ctor-dtor-privacy -W -DLIBICONV_PLUG -DDO_ICONV_CAST
     14 LDFLAGS = -L /usr/local/lib -R /usr/local/lib
2) fbreader/src/formats/fb2/FB2Reader.h
 It seems "_P" had been defined somewhere and cause enum declaration errors.
     23 #include <ZLXMLReader.h>
     24
     25 #undef _P
     26
     27 class FB2Reader : public ZLXMLReader {
3) zlibrary/core/src/unix/library/ZLibrary.cpp
Thanks to Rod Evans' great catch, I added an extra dlerror() to make sure it returns NULL before calling dlsym().
    128         void (*initLibrary)();
    129         dlerror();
    130         *(void**)&initLibrary = dlsym(handle, "initLibrary");
4) make; sudo make install
5) /usr/bin/FBReader &  (or run it from GNOME menu: start -> Office ->E-book reader)
Have fun.

Thursday, March 3, 2011

crazy CSS, thanks DTrace

I hate many enterprise applications because of very unpleasant user experiences. Here's a recent example.
When I opened an application in firefox browser, my computer nearly hanged. Using basic Solaris commands prstat, mpstat, etc, I found displaying this page caused huge number of (40K) context switches per second.
At first, I thought it might be because of some ugly javascripts. So I first checked the source of this web page, well it contains several big java script files (sum up over 1MB), then I disabled the javascript in browser, however, the problem remained. I also tried offline browsing, it didn't solve the problem, so this is not a networking issue.

What's wrong?

~# truss -c -p 1224  (#1244 is firefox process ID)
^C
syscall               seconds   calls  errors
read                     .016    3097     777
write                    .022    2126       1
open                     .000       2
close                    .000       4
fstat                    .000       2
access                   .000       1       1
ioctl                    .005    1145
fdsync                   .003       1
fcntl                    .000       6
lwp_park                 .236   28575     330
lwp_unpark               .177   28340
sigaction                .000      52
...

It looks like lwp_park/lwp_unpark are evils. Use a Dtrace script to find who caused this.

~# cat lwp_park.d
#!/usr/sbin/dtrace -qs
syscall::lwp_park:entry
/pid==$target/
{
 @[ustack()]=count();
}
END
{
trunc(@, 10);
}

./lwp_park.d -p 1244   

Then switch to the problemed web page in firefox, go back to that terminal running DTrace, type Ctrl-C.
The DTrace output the user stacks for causing both lwp_park() and lwp_unpark() which is interesting. After demangling C++ symbols, I got:

              libc.so.1`__lwp_unpark+0x19
              libnspr4.so`PR_Unlock+0x102
              libxul.so`unsigned TimerThread::RemoveTimer(nsTimerImpl*)+0x7e
              libxul.so`unsigned nsTimerImpl::Cancel()+0x32
              libxul.so`unsigned imgContainer::FrameUpdated(unsigned,nsIntRect&)+0xbd
              libxul.so`void row_callback(png_struct_def*,unsigned char*,unsigned long,int)+0x187
              libxul.so`MOZ_PNG_proc_IDAT_data+0x190
              libxul.so`MOZ_PNG_process_data+0x4ce
              libxul.so`unsigned ReadDataOut(nsIInputStream*,void*,const char*,unsigned,unsigned,unsigned*)+0x8c
              libxul.so`unsigned nsStringInputStream::ReadSegments(unsigned(*)(nsIInputStream*,void*,const char*,unsigned,unsigned,unsigned*),void*,unsigned,unsigned*)+0x47
              libxul.so`unsigned nsPNGDecoder::WriteFrom(nsIInputStream*,unsigned,unsigned*)+0x3a
              libxul.so`unsigned imgContainer::ReloadImages()+0x339
              libxul.so`unsigned imgContainer::GetCurrentFrameRect(nsIntRect&)+0x1a1
              libxul.so`unsigned imgRequest::NotifyProxyListener(imgRequestProxy*)+0x10f
              libxul.so`unsigned imgRequestProxy::Clone(imgIDecoderObserver*,imgIRequest**)+0xe7
              libxul.so`unsigned nsImageLoader::Load(imgIRequest*)+0x52

libxul.so`already_AddRefednsImageLoader::Create(nsIFrame*,imgIRequest*,int,nsImageLoader*)+0x57
              libxul.so`void nsPresContext::SetupBackgroundImageLoaders(nsIFrame*,const nsStyleBackground*)+0x98
              libxul.so`void nsCSSRendering::PaintBackgroundWithSC(nsPresContext*,nsIRenderingContext&,nsIFrame*,const nsRect&,const nsRect&,const nsStyleBackground&,const nsStyleBorder&,unsigned,nsRect*)+0x93f
              libxul.so`void nsCSSRendering::PaintBackground(nsPresContext*,nsIRenderingContext&,nsIFrame*,const nsRect&,const nsRect&,unsigned,nsRect*)+0xea
            24658

              libc.so.1`__lwp_park+0x19
              libc.so.1`cond_wait_queue+0x60
              libc.so.1`cond_wait_common+0x1eb
              libc.so.1`__cond_timedwait+0x66
              libc.so.1`cond_timedwait+0x27
              libc.so.1`pthread_cond_timedwait+0x24
              libnspr4.so`PR_WaitCondVar+0x24a
              libxul.so`unsigned TimerThread::Run()+0x11c
              libxul.so`unsigned nsThread::ProcessNextEvent(int,int*)+0x121
              libxul.so`int NS_ProcessNextEvent_P(nsIThread*,int)+0x2d
              libxul.so`void nsThread::ThreadFunc(void*)+0xa7
              libnspr4.so`_pt_root+0xe7
              libc.so.1`_thrp_setup+0x9b
              libc.so.1`_lwp_start
            26335 
The stack of lwp_unpark() is often more interesting, because lwp_park() is usually caused by waiting for a condition variable which does not directly tell you what the application is waiting for. While if there are many lwp_park(), then there are many lwp_unpark() accordingly, so I looked at lwp_unpark() stack. I'm not a browser expert, from the function name, the firefox seemed to do rendering background based on CSS.  Then I checked the CSS file which size is 150KB, Damn, there're 571 occurences like below:

{background: url(../xxx/yyy/zzz.png)} 

Then I wanted to check how many times  nsCSSRendering::PaintBackground() was called by using another DTrace script.

 From:
libxul.so`void nsCSSRendering::PaintBackground(nsPresContext*,nsIRenderingContext&,nsIFrame*,const nsRect&,const nsRect&,unsigned,nsRect*)+0xea  

#!/usr/sbin/dtrace -s
pid$target:libxul:__1cOnsCSSRenderingPPaintBackground6FpnNnsPresContext_rnTnsIRenderingContext_pnInsIFrame_rknGnsRect_9AIp7_v_:ea
{
 @ =count();
 Ran this DTrace script, and switched to the problemed web page in firefox. this time DTrace output:
~# ./pid.d -p 1244
dtrace: script './pid.d' matched 1 probe
^C
              422
It indicated rendering this web page caused the firefox painted background 422 times (via X window), crazy!!! On the other hand, it looks like firefox's libxul.so should be improved when it renders these images. It caused about 25,000 context switches. Is it because that rendering the images is in asynchronous way and the rendered data are in local memory or on fast network so that context switches occurred so fast?

Workaround: In firefox settings, Preference -> Contents -> Load images automatically -> Exceptions -> add this website to block list.