Sunday, February 27, 2011

测试硬盘IO性能的工具

hdparm - get/set hard disk parameters
测量使用bufferedIO(默认)的throughput
$ sudo hdparm -t  /dev/sda1 
/dev/sda1:
 Timing buffered disk reads:  344 MB in  3.00 seconds = 114.55 MB/sec
测量使用directIO的throughput
$ sudo hdparm -t --direct /dev/sda1 
/dev/sda1:
 Timing O_DIRECT disk reads:  572 MB in  3.01 seconds = 190.08 MB/sec

iozone - benchmark filesystem
使用directio (-I), 一共1m个record (-s 1m), 每个record 大小为4kB (-r 4k), 分64个线程来读(-t 64), 使用POSIX pthread (-T). benchmark的类型由-i指定
0=write/rewrite,
1=read/re-read,
2=random-read/write,
3=Read-backwards,
4=Re-write-record,
5=stride-read,
6=fwrite/re-fwrite,
7=fread/Re-fread,
8=random_mix,
9=pwrite/Re-pwrite,
10=pread/Re-pread,
11=pwritev/Re-pwritev,
12=preadv/Re-preadv


/localfs$ iozone -I -s 1m -r 4k -i 0 -i 2 -t 64 -T
 Iozone: Performance Test of File I/O
         Version $Revision: 3.308 $
  Compiled for 64 bit mode.
  Build: linux 

 Contributors:William Norcott, Don Capps, Isom Crawford, Kirby Collins
              Al Slater, Scott Rhine, Mike Wisner, Ken Goss
              Steve Landherr, Brad Smith, Mark Kelly, Dr. Alain CYR,
              Randy Dunlap, Mark Montague, Dan Million, Gavin Brebner,
              Jean-Marc Zucconi, Jeff Blomberg, Benny Halevy,
              Erik Habbinga, Kris Strecker, Walter Wong, Joshua Root.

 Run began: Wed Apr 20 18:07:37 2011

 O_DIRECT feature enabled
 File size set to 1024 KB
 Record Size 4 KB
 Command line used: iozone -I -s 1m -r 4k -i 0 -i 2 -t 64 -T
 Output is in Kbytes/sec
 Time Resolution = 0.000001 seconds.
 Processor cache size set to 1024 Kbytes.
 Processor cache line size set to 32 bytes.
 File stride size set to 17 * record size.
 Throughput test with 64 threads
 Each thread writes a 1024 Kbyte file in 4 Kbyte records

 Children see throughput for 64 initial writers  =   69712.78 KB/sec
 Parent sees throughput for 64 initial writers  =   53411.80 KB/sec
 Min throughput per thread    =     929.10 KB/sec 
 Max throughput per thread    =    1169.92 KB/sec
 Avg throughput per thread    =    1089.26 KB/sec
 Min xfer      =     820.00 KB

 Children see throughput for 64 rewriters  =   68695.96 KB/sec
 Parent sees throughput for 64 rewriters  =   67008.63 KB/sec
 Min throughput per thread    =     844.21 KB/sec 
 Max throughput per thread    =    1173.81 KB/sec
 Avg throughput per thread    =    1073.37 KB/sec
 Min xfer      =     744.00 KB

 Children see throughput for 64 random readers  =   79020.74 KB/sec
 Parent sees throughput for 64 random readers  =   78204.49 KB/sec
 Min throughput per thread    =    1117.41 KB/sec 
 Max throughput per thread    =    1314.01 KB/sec
 Avg throughput per thread    =    1234.70 KB/sec
 Min xfer      =     872.00 KB

 Children see throughput for 64 random writers  =   44820.63 KB/sec
 Parent sees throughput for 64 random writers  =   38207.94 KB/sec
 Min throughput per thread    =     647.45 KB/sec 
 Max throughput per thread    =     748.67 KB/sec
 Avg throughput per thread    =     700.32 KB/sec
 Min xfer      =     888.00 KB



iozone test complete.

Sunday, February 06, 2011

zsh使用心得

抛弃了tcsh开始使用zsh了一段时间.zsh的特点是:fancy. 记录一下使用的心得
参考
https://wiki.archlinux.org/index.php/Zsh
http://zshwiki.org/home/
zsh workshop

使用
export var="value"


Completion System
官方介绍
发现cd补全的时候除了local-directories以外总是会出现users的选项, 很讨厌
去掉方法:"unsetopt cdablevars"

C++笔记

继承
继承方式:
  • public: 可以被任何人访问
  • protected:可以被本类以及子类访问
  • private: 只允许本类访问
虚继承: C++支持多重继承,也就是一个类可以同时有多个直接继承的基类.如果碰到如下的继承方式
A
| \ 
B  C
 \ |
   D
也就是类B和C分别继承A,同时D继承了B和C.这时候我们就需要使用以下的方法来让B和C虚继承A:
class A {
public:
    void printA() {}
};
class B:virtual public A;
class C:virtual public A;
class D:public B,public C;
如果B和C不使用虚继承,那么最终派生类D中就有可能含有两个A的作为基类,从而产生了二义性.


类型转换


C中的类型转换可以将一种类型的指针转换为任何其他类型的指针, 比如
ptr2 = (ClassFoo*) &obj;
C++中,可以有更多的选择
  • dynamic_cast <new_type> (expression) 可以将子类指针转化为父类指针
  • static_cast <new_type> (expression)可以将相关联的类指针互相转化, 比如子类指针到父类指针,或者父类指针到子类
  • reinterpret_cast <new_type> (expression)可以将任何类型指针相互转化
  • const_cast <new_type> (expression)保证转化后的指针是const


构造函数


派生类构造函数的调用顺序 如果基类的构造函数没有参数, 那么在进入派生类构造函数之前,基类构造函数将会被自动调用. 如果基类的构造函数有参数,那么派生类需要显式的调用基类构造函数.也就是所谓的"constructor chaining". 并且由于支持多继承,C++不能象Java那样使用super()
class Derived : public Base
{
    public:
        Derived(int foo, int bar)
        : Base(foo), bar_(bar)   // Call the superclass constructor in the subclass' initialization list.
        {
            // do something with bar
        }
};
explicit 关键字explicit可以修饰构造函数, 使得"converting constructor"非法.
class A {
public:
    A(int);
};
class B {
public:
    explicit B(int);
};
main() {
    A a1 = 37; // 合法
    A a2(37);  // 合法
    B b1 = 37; // 非法
    B b2(37);  // 合法
}


析构函数


virtual 有时候类的析构函数会被virtual关键字修饰, 这样可以强迫该类的派生类对象析构的时候使用派生类的析构函数而不是基类的----哪怕该对象是当做一个基类来被引用. 注意,一般说来当一个类含有虚方法的时候, 原则上就应该让析构函数为虚----因为虚方法意味着这个类多半是作为interface来使用.
class Base {
    virtual ~Base();
};
class Derived : public Base {
    ~Derived();
};
int main()
{
    Base* p = new Derived;
    delete p; // virtual destructor used to ensure that ~Derived is called
}


成员变量/函数


virtual 使用该关键字最主要的目的在于,当使用父类型的指针指向其子类的实例的时候,可以通过通过父类的指针调用实际子类的成员函. 编译器看到virtual关键字修饰的函数时,就会使用动态绑定(dynamic binding)在运行期决定函数的入口,而不是像普通的未被virtual关键字修饰的那种函数那样在编译期就静态绑定(static binding)函数入口.比如执行下面的代码
class Base {
    public:
        void foo() { cout << "Base::foo" << endl; }
        virtual void vfoo() { cout << "Base::vfoo" << endl; }
};
class Derived: public Base{
    public:
        void foo() { cout << "Derived::foo" << endl; }
        void vfoo() { cout << "Derived::vfoo" << endl; }

};
int main() {
    Base *p;
    p = (Base*) new Derived;
    p->foo();
    p->vfoo();
}
输出为
Base::foo
Derived::vfoo
static 静态成员变量是为了让同一种类的不同实例共享数据.该静态成员变量的初始化在类外,例如
int MyClass::MyStaticVar = 1;
静态成员函数与普通成员函数区别在于没有this指针,所以无法得知是针对哪个实例的操作.因此静态成员函数只能访问静态成员变量. 静态成员函数也不能被virtual, const, volatile, 以及const volatile所修饰. const 被const修饰的成员函数无法是read-only, 不能修改任何调用者的成员.
class Test {
    public:
        int test;
        void foo() {test = 1;} // 合法
        void cfoo() const {  test = 1;} //非法
};
const不能修饰构造和析构函数,并且不能被非const函数重载.


inline inline函数在编译期被替换至caller的代码中,所以节省了函数调用的开销.在 C++当中,尽量用inline而不是#define.inline的成员函数定义必须在头文件中,

ref: http://www.parashift.com/c++-faq-lite/inline-functions.html#faq-9.1


变量


const 用于声明那些编译期就可以确定值的变量,这样的编译器可以比用C中的#define替换要知道更多的信息,从而给出更给力的报错信息.用const声明的变量必须立即赋值--否则之后无法对该变量进行赋值或者修改.
int main() {
   const int i = 5;
   i = 10;   // 非法
   i++;   // 非法
}

ref http://duramecho.com/ComputerInformation/WhyHowCppConst.html
volatile 用volatile关键字修饰一个变量是为了通知compiler不要对这个变量进行优化----因为这个变量可能被其他thread或者被系统使用.


模版(Template)


模版类的实现必须包括在.h文件中,否则编译的时候会找不到模版类的实现.
具体原因参见http://www.parashift.com/c++-faq-lite/templates.html#faq-35.12
参数 Template可以使用class,typename参数,也可以使用非类型变量比如一个int或者char变量
template <class C, typename T, int N>
class myclass {
    T seq[N];
};
继承模版类
template <typename T>
class Base {
    T seq[N];
};
template <typename T>
class Derived: public Base< T > {
};

Tuesday, February 01, 2011

rubber

用法
rubber是一个latex的wrapper. 它免去了你先把eps -> pdf, 再latex paper.tex, 再bibtex paper 再 latex paper.tex这个复杂的过程. 你只需要一个命令就能完成
$rubber paper

问题/解决
不同的版本/平台上, rubber可能会有一些问题:
1 eps转pdf的时候报错
GS_OPTIONS=-dPDFSETTINGS=/prepress rubber --pdf -Wrefs -Wmisc paper
running: epstopdf --outfile=aaa.pdf aaa.eps...
Traceback (most recent call last):
  File "/usr/local/bin/rubber", line 4, in 
    sys.exit(Main()(sys.argv[1:]))
  File "/Library/Python/2.6/site-packages/rubber/cmdline.py", line 319, in __call__
    return self.main(cmdline)
  File "/Library/Python/2.6/site-packages/rubber/cmdline.py", line 283, in main
    ret = env.final.make(self.force)
  File "rubber/depend.py", line 157, in make
  File "rubber/depend.py", line 171, in make
  File "rubber/depend.py", line 276, in run
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 595, in __init__
    errread, errwrite)
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 1106, in _execute_child
    raise child_exception
OSError: [Errno 8] Exec format error
make: *** [pdf] Error 1

修改/usr/local/share/rubber/rules.ini
command = epstopdf --outfile=$target $source
改为
command = bash epstopdf --outfile=$target $source

2 无法使用bibtex
在我的Mac上, bibtex后面不能使用绝对路径(Ubuntu上则是好的, 很诡异).所以导致我rubber以后所有reference都不对.

Monday, January 24, 2011

gmail tips

http://email.about.com/od/gmailtips/qt/et_find_mail.htm

所有标题含有hi的邮件 "subject:hi"
所有从apc999处来信 "from:apc999"
所有寄给apc999的来信 "to:apc999"
所有未读邮件 "is:unread"
所有starred邮件 "is:starred"
2005年5月5日以前邮件 "before:2005/05/05"
2005年5月5日以后邮件 "after:2005/05/05"

Wednesday, January 19, 2011

Java笔记

Managing Source and Class Files
Java的Package概念

编译例子
javac -classpath /path/to/foo/foo.jar:./bar.jar \
      -d /path/to/mine/MyStuff_classes MyStuff.java
-classpath: 指定需要的其他目录或者jar文件
-d dirname: 按照class的packagename创建目录结构,把class文件放入相应的目录. 比如MyStuff.java是org.apc999.MyStuff, 那么按照上面的命令, 则会生成目录/path/to/mine/org/apc999/MyStuff.class

make MyStuff.jar
jar cvf MyStuff.jar -C MyStuff_classes/ .

Tuesday, January 11, 2011

[Linux]pthread

文档

史上最好的pthread Tutorial/Reference


使用

Thread
pthread_t mythread;
pthread_create(&mythread, NULL, myfunc, NULL);
pthread_join(mythread, NULL);
Mutex
1 初始化一个mutex有两种方式, 可以动态的声明:
pthread_mutex_t mymutex
pthread_mutex_init(&mymutex, NULL); 
也可以静态的声明:
pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
2 使用mutex来serialize一段程序. mutex就好比一把锁,被锁住的程序段(pthread_mutex_lock和pthread_mutex_unlock两个语句间的code)在同一时间只能被一个thread执行. 其他需要执行这段程序的thread都会在pthread_mutex_lock这里被卡住,直到mutex被unlock才能有一个thread接着往下执行.
pthread_mutex_lock (&mymutex);
dotstr.sum += mysum;
pthread_mutex_unlock (&mymutex);
3 销毁一个mutex
pthread_mutex_destroy(&mymutex);

Spinlock
spinlock是轻量级的lock机制,比较mutex等机制,节省了process re-scheduling以及context switch等开销,所以如果确信thread不会被block很久,spinlock会非常有效.

1 申明一个spinlock
pthread_spinlock_t myspinlock;
pthread_spin_lock(&myspinlock);
2 使用spinlock上锁
pthread_spin_lock(&myspinlock);
critialnum += 1;
pthread_spin_unlock(&myspinlock);
3 销毁
pthread_spin_destroy(&myspinlock);

在MacOS 上, spinlock的原语与linux上的有所不同.
#include <libkern/osatomic.h>
OSSpinLock mylock = OS_SPINLOCK_INIT;
OSSpinLockLock(&mylock);
OSSpinLockUnlock(&mylock);

Misc

Linux上thread的实现和其他UNIX系统有一个重要区别: Linux上pthread_create实际上用一个process来运行一个thread. 所以每个thread都有自己的pid,也有自己的tid.同一个进程中的thread有同样的pid但是不同的tid. 可以用下面的代码查看pid或者tid
fprintf (stderr, "thread pid is %d\n", (int) getpid ());
fprintf (stderr, "thread tid is %d\n", (int) gettid ());

Thrift笔记

文档

Thrift的文档真是不是一般的incomplete 基本上可以说是空白. Facebook不知道干什么去了. 这是我找到的有点帮助的文档:
官方的文档: Using Thrift with C++,
网上其他的: A Intro to Thrift

安装
Thrift 的C++编译器使用了boost,所以你如果要用Thrift配合C++使用的话, 需要先安装boost.
然后下载thrift源代码,编译安装(configure, make, make install),按下不表.

HelloWorld (C++版)

第一步:用thrift描述一个service的接口,比如在Server端提供这样一个函数叫ping, Client端可以通过rpc调用ping这个函数(在thrift帮你marshall这些rpc call),ping会在Server端执行.

namespace cpp Test
service HelloWorld {
  oneway void ping()
}
将这个文件存为比如apc999.thrift. 现在把编译apc999.thrift成C++代码
$thrift --gen cpp apc999.thrift
$ls
gen-cpp/  HelloWorld.thrift/
$ls gen-cpp
apc999_constants.cpp  apc999_types.cpp  
HelloWorld.cpp  HelloWorld_server.skeleton.cpp
apc999_constants.h    apc999_types.h    
HelloWorld.h
在gen-cpp这个目录中, 我们会发现一堆thrift生成的文件. 其中HelloWorld开头的都是和HelloWorld这个service有关, 你可以在apc999.thrift中定义多个service.他们会生成不同的文件. 而apc999开头的是一些常量和类型的定义.

我们需要记住的是: Thrift帮你生成了给定Service的服务器端和客户端代码.Thrift这里的命名规则是对于Service XYZ, 它对应的服务器端代码(具体这个Service的执行)在类XYZHandler中,客户端代码(负责marshall, execute RPC)在类XYZClient中. 所以你需要用这个服务, 你只需要直接修改或者继承这些类.

第二步:编写Server端代码. thrift帮我们生成的HelloWorld_server.skeleton.cpp就是Server端代码的模板. 我们只需要往里面添加我们需要的功能实现. 比如我们添加了一行
// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.
#include "HelloWorld.h"
#include <protocol/TBinaryProtocol.h>
#include <server/TSimpleServer.h>
#include <transport/TServerSocket.h>
#include <transport/TBufferTransports.h>

using namespace ::apache::thrift;
using namespace ::apache::thrift::protocol;
using namespace ::apache::thrift::transport;
using namespace ::apache::thrift::server;

using boost::shared_ptr;
using namespace Test;

class HelloWorldHandler : virtual public HelloWorldIf {
 public:
  HelloWorldHandler() {
    // Your initialization goes here
  }

  void ping() {
    // Your implementation goes here
    printf("Hello World!\n"); //目前为止我修改的唯一一行
  }
};

int main(int argc, char **argv) {
  int port = 9090;
  shared_ptr<HelloworldHandler> handler(new HelloWorldHandler());
  shared_ptr<TProcessor> processor(new HelloWorldProcessor(handler));
  shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));
  shared_ptr<TTransportfactory> transportFactory(new TBufferedTransportFactory());
  shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());

  TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);
  server.serve();
  return 0;
}
这个Server端代码有main函数, 所以你完全可以编译这个程序并运行.它会在9090端口监听. 如果有rpc调用ping这个函数, 它会打印出"Hello World!".

第三步:编写客户端代码.
#include "HelloWorld.h"  // HelloWorldClient这个类在helloWorld.h中被申明

#include <transport/TSocket.h>
#include <transport/TBufferTransports.h>
#include <protocol/TBinaryProtocol.h>

using namespace apache::thrift;
using namespace apache::thrift::protocol;
using namespace apache::thrift::transport;

using namespace Test;

int main(int argc, char **argv) {
  boost::shared_ptr<TTransport> socket(new TSocket("localhost", 9090));
  boost::shared_ptr<TTransport> transport(new TBufferedTransport(socket));
  boost::shared_ptr<TProtocol> protocol(new TBinaryProtocol(transport));

  HelloWorldClient client(protocol);
  transport->open();
  client.ping();
  transport->close();

  return 0;
}

Tips

Thrift生成的server端是thread safe的. 但是client端不是thread safe. 所以需要多个thread和server端通信,则每个thread需要initiate一个自己的client实例.

使用Thrift的C++库有,server端有4种不同的选择: TSimpleServer,TThreadedServer, TThreadPoolServer,以及TNonblockingServer.

当有server和client间有大量的network traffic的时候,可以使用Nagles算法来优化网络性能. Nagles算法通过缓冲来减少收发的packet数目.在Thrift中使用Nagles算法,我们只需要将上面例子中的客户端代码中下面的语句
boost::shared_ptr<TTransport> socket(new TSocket("localhost", 9090));
改为
TSocket* sock = new TSocket("localhost", 9090);
boost::shared_ptr<TTransport>  socket(sock);
然后在调用transport->open();之前 先调用sock->setNoDelay(false);就可以了

Wednesday, January 05, 2011

[Python]Package的安装

1 使用python setup.py install来安装

使用python setup.py install的时候, 默认路径是 /usr/lib/python2.x/site-packages 这样的全局路径底下. 若是没有权限写,可以自己指定安装路径
python setup.py install --home=/your/fav/dir
比如
python setup.py install --home=~


2 使用easy_install来安装egg文件
easy_install foo.egg 

Sunday, January 02, 2011

Firefox tips

给Firefox(3.5,4) 最后一个tab加上close按钮:
地址栏内键入"about:config",回车
搜索"browser.tabs.closeWindowWithLastTab",将Value设为false

Tuesday, December 21, 2010

[Linux]同步ubuntu上的时间

$ sudo aptitude install rdate
$ sudo rdate -s clock-1.cs.cmu.edu
$ sudo hwclock --systohc 

[Emacs]在Emacs中使用gdb

在Emacs中使用gdb调试程序 (推荐)
http://www.inet.net.nz/~nickrob/
An Introduction To Using GDB Under Emacs


1 M-x gdb 回车

2 Run gdb (like this): gdb --annotate=3 myprogname 回车
如果使用的是emacs 23.1 比如ubuntu 10.10当中的emacs-snapshot, 如下
Run gdb (like this): gdb -i=mi myprogname 回车

Gud->GDB-MI->Display other windows

Tuesday, November 16, 2010

[Python]String的decode, encode

string的decode用法:
str.decode(encoding="gb2312",errors="strict"
在这里我们告诉python解释器用encoding参数所指定的来对str解码.标准的encoding可以查看这里

和简体中文相关的通常有gb2312,gb18030以及gbk(大多数BBS的中文encoding)

一篇参考http://hi.baidu.com/tornadory/blog/item/2fa5f0c36cf7bd5fb219a801.html

[Linux]Profiling

gprof

gprof是GNU的profiling工具,使用的时候需要编译期的支持
使用:
1 编译:时需要使用"-pg"选项
$cc -g -c myprog.c utils.c -pg
$cc -o myprog myprog.o utils.o -pg
如果加上了"-g"选项(如上),则可以支持Line-by-line Profiling
2 运行: 执行生成的可执行文件(比如上面的myprof), 这时会生成一个"gmon.out"的文件
3 查看: 用gprof 查看profiling结果
$gprof myprof | more
参考:
gprof Quick-Start Guide

perf

perf是Linux下非常强大的profiling工具,也非常好用.
perf类似于git那样,有一堆子命令,比较常用的有record,report,annotate,stat等.
运行一个程序foo并记录下profile(默认为perf.data):
$ sudo perf record ./foo
读取刚才生成的profile结果(默认perf.data)并显示分析结果:
$ sudo perf report
输出结果类似
    49.97%  foo  filter_bench         [.] main
     5.31%  foo  libc-2.12.1.so       [.] 0x7aeab
     0.36%  foo  libstdc++.so.6.0.15  [.] operator new[](unsigned long)
注意这里libc-2.12.1.so中的symbol没有被load进来,所以无法显示具体的函数名而只能看见一个入口地址0x7aeab.
在ubuntu/debian上你可以安装libc6-dbg(注意不是libc6-dev)帮助gdb,perf这样的工具traceback.libc6-dbg包含了libc6的debug信息
$ apt-get install libc6-dbg
显示annotated code
$ sudo perf annotate
运行一个命令并查看硬件counter:
$ perf stat --repeat 10 -e cycles:u \
-e instructions:u -e l1-dcache-loads:u -e l1-dcache-load-misses:u ./foo
查看所有支持的硬件counter:
$ perf list
参考:
Linux kernel profiling with perf

OProfile

OProfile利用硬件支持来profile系统或者application. 与gprof不同,OProfile不会在binary中添加指令
启动:
1 加载oprofile
$sudo opcontrol --init
2 设置是否需要profile kernel,如果需要
$sudo opcontrol --vmlinux=/boot/vmlinux-`uname -r`
如果不需要
$sudo opcontrol --no-vmlinux
3 开始采集数据
$sudo opcontrol --start 
Using default event: CPU_CLK_UNHALTED:100000:0:1:1
Using 2.6+ OProfile kernel interface.
Using log file /home/apc999/tempsession/samples/oprofiled.log
Daemon started.
Profiler running.
4 查看oprofile状态
$sudo opcontrol --status
Daemon running: pid 13892
Separate options: none
vmlinux file: none
Image filter: none
Call-graph depth: 0
5 结束采集数据
$sudo opcontrol --stop 
6 结束oprofile daemon
$sudo opcontrol --shutdown 

参考:
OProfile Manual

Sunday, October 31, 2010

[Linux]用gs合并几个pdf文件

gs -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile=finished.pdf file1.pdf file2.pdf

Thursday, October 21, 2010

PPT 热键

Press F5 in PowerPoint/Windows or Control-Shift-S in PowerPoint X/Mac to start a slide presentation from the beginning

Press Shift+F5 in PowerPoint 2003 or Control+Shift+B in PowerPoint X/Macintosh to start a presentation from the current slide

Friday, October 15, 2010

手机配置

Apple iPhone 4
  • CPU: Apple A4 - fully compatible with ARM Cortex-A8, running at 1 GHz, 64 L1 Cache, 640 L2 Cache
  • Memory: 512 MB eDRAM
  • Storage: 16 GB or 32 GB flash memory
Nokia N900
  • CPU: ARM Cortex-A8, running at 600 MHz
  • Memory: 256 MB
  • Storage: 32 GB internal; Expandable to up to 48 GB with an external microSD card

Thursday, October 14, 2010

Cocoa编程笔记(update中)

Cocoa是Mac上使用的图形界面framework, 简单说来就是一个库使开发人员可以定制自己的基于GUI的 Application。Cocoa使用的语言是Object-C(参见我的Object-C笔记)。 Cocoa编程的学习曲线比其他GUI编程的要陡,因为有很多概念要理解。我在学习过程中,参照如下的一些tutorial或者文档:

Cocoa Fundamental Guide:这是最核心最基础的文档。介绍了最重要的概念

Cocoa Event Handling:Cocoa中如何处理事件

Introduction to Text System User Interface Layer,介绍了比如如何programatically 创建一个NSTextView,添加至NSScrollView,如何调整Text边距等等.

Introduction to Text Editing Programming Guide for Cocoa, 介绍如何使用Cocoa的Text System来完成编辑工作,比如key binding, 如何delegate message等.

一个简单界面的Cocoa Application:最最简单的一个Application.如果想学习一个最简单的Cocoa Application,从这个文档看起.

Model-View-Control模型

Cocoa中广泛使用了MVC这种的Design Pattern,把一个application功能分解为如下三个部分:

Model objects: 负责逻辑处理,不直接和用户界面打交道
View objects: 用户界面.比如label, textfield等
Controller objects: 连结Model和View, 比如处理界面送来的用户action,应用后台逻辑做出update等


内存管理
alloc, init, dealloc, retain, release, autorelease. 所有从NSObject继承而来的类都有这些方法,这些涉及到内存管理.

alloc: 从内存中分配一块内存,但仅仅是获得一块内存空间,未作任何初始化
init:初始化一个类,类似于C++中的构造函数,一般和alloc配合使用:
id  myObject = [[NSString alloc] init];
dealloc: 销毁一个类,释放内存空间
[myObject dealloc];
retain: 将一个对象的引用计数加1
[myObject retain];
release: 将一个对象的引用计数减1
[myObject release];
autorelease:每当一个对象得到autorelease消息,这个对象就将被添加到autorelease pool当中. 当改eventloop结束时,所有autorelease pool当中的对象将被release.通常一个method要返回一个对象的时候,autorelease这个对象是个好主意.
- (NSString)autoreleasedString
{
  NSString *string = [[NSString alloc] initWithString:
      @"The Sender of this message will never see this string…"];
  [string autorelease]; // we have to do this or we'll get a memory leak
  return string;
}


神秘的IBAction和IBOutlet?

经过预处理以后,IBAction实际上就是void而IBOutlet实际上根本就是一个空的宏(见定义在NSNibDeclarations.h).它们的作用是在于作为一种syntax sugar,提醒Interface Builder,"嗨,这几个被我修饰的变量或者函数是你应该知道的~".



事件处理(Event Handling)
有两种Message: 由外部设备比如键盘或者鼠标发起的Event message,以及由其他对象发起的Action message.

Event message 通常已知,所以NSResponder提供了声明以及缺省的实现.
NSResponder是一个抽象类.而Cocoa中最核心的三个类NSApplication, NSWindow, 以及 NSView都继承了NSResponder.

比如我们要处理mouseDown这个事件,我们可以继承一个NSView类(或者NSView的子类,比如NSTextView,NSTabView),然后重载mouseDown:这个方法。如果一个NSWindow上有多个NSView(或其子类), 则应该重载最上面的View,否则盖在底下的不能接受到该消息

- (void)mouseDown:(NSEvent *)theEvent {
    // determine if I handle theEvent
    // if not...
    [super mouseDown:theEvent];
}


Delegate
Common mistakes with delegation in Cocoa
一个在NSImageView中delegate mouseDown等消息的例子:
http://it.toolbox.com/blogs/macsploitation/adding-delegates-to-nsviews-21138

Text System
NSTextStorage 是NSMutableAttributedString的子类. 一般作为NSTextView 的text repository. Introduction to Text System Storage Layer Overview

NSTextView 和用户打交道的界面
NSTextContainer:Introduction to Text Layout Programming Guide


NSScrollView: Introduction to Scroll View Programming Guide for Cocoa
NSClipView:


NSParagraphStyle:Introduction to Rulers and Paragraph Styles

一个超级简单的Cocoa Text System Application
HelloWorld.h:
#import 

@interface HelloWorld : NSObject  {
    NSWindow *window;
 
 NSTextStorage *textStorage;
 NSLayoutManager *layoutManager;
 NSTextContainer *textContainer;
 NSTextView *textView;
}

@property (assign) IBOutlet NSWindow *window;

@end
HelloWorld.m
#import "HelloWorld.h"

@implementation HelloWorld

@synthesize window;

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
 // Insert code here to initialize your application 
 
 //setup textStorge
 textStorage = [[NSTextStorage alloc] initWithString:@"123abcde\n456"];
 
 //setup layoutManager
 layoutManager = [[NSLayoutManager alloc] init]; 
 [textStorage addLayoutManager:layoutManager]; 
 [layoutManager release];
 
 //setup textContainer
 NSRect cFrame = [[window contentView] frame];  
 textContainer = [[NSTextContainer alloc] initWithContainerSize:cFrame.size];
 [layoutManager addTextContainer:textContainer]; 
 [textContainer release];
 
 //setup textView
 textView = [[NSTextView alloc] initWithFrame:cFrame textContainer:textContainer]; 
 [window setContentView:textView]; 
 [window makeKeyAndOrderFront:nil]; 
 [textView release];
}

@end


常用数据结构:
NSArray: 类似list, 不能添加元素
Objective-C Tutorial: NSArray读取index位置的元素
[myArray objectAtIndex:index]

NSMutableArray:一个类似python中list的存在.可以通过addObject:来添加元素.

NSDictionary
NSMutableDictionary:一个类似于python中dict的存在,提供setObject:forKey:和removeObjectForKey:


Do things Programatically

获取中文encoding
http://www.cocoadev.com/index.pl?CharacterEncoding
NSStringEncoding gb18030 = CFStringConvertEncodingToNSStringEncoding 
    (kCFStringEncodingGB_18030_2000);
用中文encoding读文件
[options setObject:absoluteURL
    forKey:NSBaseURLDocumentOption];
[options setObject:[NSNumber numberWithUnsignedInteger:gb18030] 
    forKey:NSCharacterEncodingDocumentOption];
[options setObject:NSPlainTextDocumentType
    forKey:NSDocumentTypeDocumentOption];
 
NSAttributedString *fileContents = [[NSAttributedString alloc]
      initWithURL:absoluteURL options:options 
    documentAttributes:NULL error:outError];
NSTextView背景设为透明
[[textView enclosingScrollView] setDrawsBackground:NO];
[textView setDrawsBackground:NO];
NSImageView显示图片
NSImage *image = [NSImage imageNamed:@"yellow_background.bmp"];
[imageView setImage: image];
给NSTextView和NSTextContainer之间添加空白区域
[myNSTextView setTextContainerInset:NSMakeSize (width, height)];
使用NSLog,NSAssert输出信息,帮助调试
NSLog(@"init, %p, %p",backgroundImage, textView);
NSAssert([myWindow delegate] == self, @"You forgot to connect the window delegate.!");

NSLog 格式化字符串


其他
If you want to name your NSDocument subclass something other than MyDocument (the default name), change the name in Interface Builder and wherever it occurs in the Document header (.h) and implementation (.m) files. You must also change the name under the NSDocumentClass key in the Info.plist file.

http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/TextArchitecture/Tasks/TextEditor.html#//apple_ref/doc/uid/20001798-CJBHAJJJ

Monday, October 11, 2010

[Math]凑硬币

有6分9分和25分的硬币,不能用这3种硬币凑出来的面值最大是多少

Sol: General problem 叫 Coin Problem

对于这题, 考察面值N分
(1) N = 3k, 当k>1的时候都可以用6和9凑出来
(2) N = 3k + 1, 当k>=10的时候, N-25是3的倍数且大于等于6,可以用(1)得出
(3) N = 3k + 2, 当k>=18的时候, N-50是3的倍数且大于等于6,可以用(1)得出

所以最大不能表出的面值为53

Sunday, October 03, 2010

[Math]扔骰子

Q: 能否重新设计两个六面骰子,每个骰子上是正整数并且两个骰子之和的分布与两个正常骰子之和相同(Is it possible to change the numbers on two six sided dice to other positive numbers so that the probability distribution of their sum remains unchanged?)

Sol: 考虑两个普通骰子之和的分布的generating function:
(x/6+x^2/6+x^3/6+x^4/6+x^5/6+x^6/6)*(x/6+x^2/6+x^3/6+x^4/6+x^5/6+x^6/6)
= (x/6+2*x^2/6+2*x^3/6+x^4/6)*(x/6+x^3/6+x^4/6+x^5/6+x^6/6+x^8/6)

也就是说可以设计第一个骰子的六面为(1,2,2,3,3,4),第二个骰子的六面为(1,3,4,5,6,8)
这样可以满足新的骰子的和的分布和从前相同