顯示文章

這裡允許您檢視這個會員的所有文章。請注意, 您只能看見您有權限閱讀的文章。


主題 - Yamaka

頁: [1] 2 3 ... 13
1
假設有類似這樣的 yml
代碼: [選擇]
web0:
  build: web-base

web01:
  image: web0
  。。。。。

web02:
  image: web0
  。。。。。

web03:
  image: web0
  。。。。。

docker-compose up -d 後會建立1個image,3個containers 並執行
有沒有可能就是 web0 只是建立 image, 然後不建立容器也不跑容器
也就是實際上只跑 web01 & web02 這兩個容器
web0 單純只做 base image 用

當然,我可以把 web0 另外直接用 Dockerfile 建立
或是另外放在獨立的 web-base.yml 裡
只是想,目前的 docker-compose 版本(1.9.0)有沒有可能直接做到上面說的  ::)

2
之前有在 ~/.bashrc 顯示分支, 參考這個

http://phorum.study-area.org/index.php/topic,71755.0.html

今天加了一些功能, 在 git add . 之後能自動過瀘掉編譯後的 elf 檔
修改 parseGitBranch()

代碼: [選擇]
parseGitBranch() {
  BNAME1=$(git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\[\1\]/')
  BNAME2=$(git branch 2>&1 | sed -n -e '1 s/^\(fatal\: Not a git repository\).*/\1/p')
  # BNAME2 == "" is git && no branch
  if [ ! -z "$BNAME1" -a -z "$BNAME2" ]; then
    echo $BNAME1
  elif [ -z "$BNAME1" -a ! -z "$BNAME2" ]; then
    # Not a git repository
    echo ""
  else
    # 未曾 commit 沒有 master
    echo "[*]"
  fi
 
  # 新增開始
  LATEST_GIT_CMD="$(history|tail -n2|grep 'git ad[d]')"
  if [ ! -z "$LATEST_GIT_CMD" ]; then
    for tf in $(git status|grep "new file"|awk -F':' '{print $2}'|sed 's/^[ \t]*//')
    do
      if [ ! -z "$(file "$tf"|grep 'ELF')" ]; then
        echo "$tf" >> "$(git rev-parse --show-toplevel)/.gitignore"
        GIT_RM=$(git rm --cached "$tf")
      fi
    done
  fi
}

1. 先判斷上個指令是否為 git add
2. 用 git status 抓出新加入的檔名
3. 用 file 指令檢查是否為 ELF 檔
4. rm elf 檔並將檔名加入 .gitignore

3
無意間在網路上看到 terminal 提示字串上顯示 git 分支名
哇!!這個好,這樣就不用常常打指令確認目前所在分支
於是就撈了起來再加工,不同狀態用不同顏色顯示...

$ vim ~/.bashrc
代碼: [選擇]
parseGitBranch() {
  BNAME1=$(git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\[\1\]/')
  BNAME2=$(git branch 2>&1 | sed -n -e '1 s/^\(fatal\: Not a git repository\).*/\1/p')
  # BNAME2 == "" is git && no branch
  if [ ! -z "$BNAME1" -a -z "$BNAME2" ]; then
    echo $BNAME1
  elif [ -z "$BNAME1" -a ! -z "$BNAME2" ]; then
    # Not a git repository
    echo ""
  else
    # 未曾 commit 沒有 master
    echo "[*]"
  fi
}

parseGitStatus() {
  git status -s 2> /dev/null | tail -1 | awk 'END {if (NR==0) print 70} /^\?/ {print 201;next} /^.*/ {print 1;next}'
}

color_prompt=yes
if [ "$color_prompt" = yes ]; then
    #PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
    PS1='${debian_chroot:+($debian_chroot)}\[\033[38;5;208m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[38;5;$(parseGitStatus)m\] $(parseGitBranch)\[\033[00m\]\$ '
else
    PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi

看起來像這樣

xxxxx@xxxxx:~/local/pl [master]$


parseGitBranch() 是抓分支名
parseGitStatus() 設定分支名顏色,目前我只分3種顏色
測試半天,還算可以正常顯示 ^__^

4
qmake 預設使用 g++ 編譯(linux 環境)

這兩年來用 clang 習慣了(編譯訊息較人性化 XD)
所以就修改 *.pro 目己加入這幾行

QMAKE_CC = clang
QMAKE_CXX = clang++
QMAKE_LINK = clang++

不過每次跑 qmake -project 後修改的東西就被清掉
於是就想說能在跑 qmake -project 時自動加入設定

代碼: [選擇]
$ vim ~/.bashrc
.....
alias qmake-pro='qmake -project && printf "\nQMAKE_CXXFLAGS += -std=c++14\nQT += widgets\nQMAKE_CC = clang\nQMAKE_CXX = clang++\nQMAKE_LINK = clang++\n" >> "$(basename $(pwd)).pro"'

這樣就可以在命令列直接用 qmake-pro 指令

QT += widgets

這個 qmake 預設也沒有,所以也加進去
另外也加了支援 c++14 的設定

$ qmake-pro

5
參考: http://doc.qt.io/qt-5/qstring.html

arg() 參數除了『字串』類型最多可用9個(大於9個 編譯錯誤)外,其他類型每次只能用一個

代碼: [選擇]
std::cout << QString("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10")
               .arg("a", "b", "c", "d", "e", "f", "g", "h", "i", "j").toStdString() << std::endl;

引用
(clang)
error: no matching member function for call to 'arg'

第10個要另外再用一個 arg()

代碼: [選擇]
std::cout << QString("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10")
               .arg("a", "b", "c", "d", "e", "f", "g", "h", "i")
               .arg("j").toStdString() << std::endl;

這樣就可以編譯過了

引用
output:
a b c d e f g h i j

---
不同型別的參數不能放在同一個 arg(),

代碼: [選擇]
std::cout << QString("%1 %2 %3 %4 %5").arg("abc", "def").arg(315, 6, 16).toStdString() << std::endl;
第2個 arg(315, 6, 16) 會以為是有3個要輸出的整數,其實是誤會,參考官網函數原型就知道
如果第一個參數是整數類型,也就是說要輸出的是整數,第2個參數是『欄位寬度』,
第3個參數則是『進位』制,所以上面這行程式碼實際輸出是這樣

引用
output:
abc def    13b %4 %5

315 會轉換成16進位制,輸出時數值本身佔3個字元,所以前面補3個空白,如果不想用空白,可加第4個參數指定,像這樣

代碼: [選擇]
std::cout << QString("%1 %2 %3 %4 %5").arg("abc", "def").arg(315, 6, 16, QChar('-')).toStdString() << std::endl;
引用
output:
abc def ---13b %4 %5


如果 6, 16 也是要做為一般整數輸出,每個整數要單獨使用一次 arg()

代碼: [選擇]
std::cout << QString("%1 %2 %3 %4 %5").arg("abc", "def").arg(315).arg(6).arg(16, 0, 16).toStdString() << std::endl;
引用
output:
abc def 315 6 10


~/cc/qt/test1$ cat main.cc
代碼: [選擇]
#include <QString>
#include <iostream>

int main() {
  std::cout << QString("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10")
                 .arg("a", "b", "c", "d", "e", "f", "g", "h", "i").arg("j").toStdString() << std::endl;
 
  std::cout << QString("%1 %2 %3 %4 %5").arg("abc", "def").arg(315, 6, 16).toStdString() << std::endl;
  std::cout << QString("%1 %2 %3 %4 %5").arg("abc", "def").arg(315, 6, 16, QChar('-')).toStdString() << std::endl;
  std::cout << QString("%1 %2 %3 %4 %5").arg("abc", "def").arg(315).arg(6).arg(16, 0, 16).toStdString() << std::endl;
  return 0;
}
引用
~/cc/qt/test1$ qmake -project
~/cc/qt/test1$ qmake
~/cc/qt/test1$ make
~/cc/qt/test1$ ./test1
a b c d e f g h i j
abc def    13b %4 %5
abc def ---13b %4 %5
abc def 315 6 10



6
最近在 ubuntu-mate 15.04 環境用 pluma 寫 go 碼
可惜的是 pluma 預設未支援 go 語法

代碼: [選擇]
$ find /usr/share -type f -name '*.lang'|grep go
/usr/share/gtksourceview-3.0/language-specs/go.lang
$

pluma 用的是 gtksourceview-2.0
但是 gtksourceview-2.0 沒找到 go.lang
設定方式是直接建立 3.0 版的 go.lang 連結到 2.0 版就可以

代碼: [選擇]
$ sudo ln -s /usr/share/gtksourceview-3.0/language-specs/go.lang /usr/share/gtksourceview-2.0/language-specs/go.lang
重新開啟 pluma 後就有支援 golang 語法了 ^__^

參考網址:https://ubuntu-mate.community/t/adding-syntax-highlighting-to-pluma/56/1


7
雜七雜八 / 終於合體了 XD
« 於: 2016-03-23 12:56 »
https://sourceforge.net/projects/ubuntubsd/

擁有 freebsd 的心 加上 ubuntu 的外表  :D

Features
引用
Versatile text based installer
Xfce desktop included
Ubuntu based
Debian based
FreeBSD based
Suitable for desktops and server alike
ZFS support completely integrated

8
雜七雜八 / 今天真的冷啊!!
« 於: 2016-01-23 11:09 »
今天真的有夠冷
桌機CPU風扇一直在0RPM
害我一直以為是不是風扇掛了  :D

大家要包暖一點喔!^___^

9
好久以前試過一次,不過沒試出來,今天再拿出來玩,終於弄出來了XD

目標是這樣:編寫好 c/c++ 程式碼之後,不手動跑 make 或是 gcc/g++ 編譯,
而是直接改原始碼的權限為可執行,然後就.....直接執行這個檔,例如:

代碼: [選擇]
$ cat ex045.cc

#include <iostream>
 
int main(int argc, char **argv) {
  std::cout << "Hello, World!!\n"
            << argc << "\n" << argv[1] << " " << argv[2]
            << std::endl;
  return 0;
}

引用
$ chmod +x ex045.cc
$ time ./ex045.cc 123 abc
Hello, World!!
3
123 abc

real   0m0.365s
user   0m0.304s
sys   0m0.048s


沒錯,就是要能夠直接跑 ./ex045.cc,不是編譯後的 ./ex045
中間測試過程就略過不提了,直接貼結果出來

代碼: [選擇]
$ cat ex045.cc

//bin/true;CCE=$0;CCE="${CCE##*/}";CCE="/tmp/cc/${CCE%%.*}";[ ! -d "/tmp/cc" ]&&mkdir /tmp/cc/;if [ ! -f ${CCE} ] || [ `date -r $0 +%s` -gt `date -r ${CCE} +%s` ]; then /usr/bin/env clang++ -O3 -std=c++14 -o ${CCE} $0;fi; ${CCE} $@;exit
#include <iostream>
 
int main(int argc, char **argv) {
  std::cout << "Hello, World!!\n"
            << argc << "\n" << argv[1] << " " << argv[2]
            << std::endl;
  return 0;
}

跟其他 shell script 一樣,第一行對 c++ 來說是是註解
但卻是一串 bash 指令,這些指令會判斷原始碼與執行檔的檔案時間
必要的話就啟動編譯器編譯進行編譯,執行檔則丟到 /tmp/cc
最後再執行 /tmp/cc 資料夾裡的執行檔
這行最後面的『 exit 』指令是必要的
少了這行,bash 會一直往下讀取指令並執行...

第一次執行會先進行編譯,如果程式碼未修改過
之後再執行就不會編譯(直到 reboot)

引用
$ time ./ex045.cc 123 abc
Hello, World!!
3
123 abc

real   0m0.365s
user   0m0.304s
sys   0m0.048s
$ time ./ex045.cc 123 abc
Hello, World!!
3
123 abc

real   0m0.022s
user   0m0.008s
sys   0m0.008s



10
程式討論版 / [Golang] select-case
« 於: 2015-09-06 15:41 »
select case 每次都會隨機選擇一個已進入『備妥』狀態的 case 來執行
而且每一輪進入 select 時,每一個 case 被選中的機率都一樣
不會輪流選擇,完全是隨機。

下面範例是網路上抓來修改的
每個 case 增加一個計數器
最後將進入每個 case 的次數印出

從執行結果可以看到,每次進入 select
每一個 case 後的函數都會被呼叫一次
但是最後只會隨機選擇一個 case 進入

Code:
代碼: [選擇]
package main

import (
  "fmt"
)

func main() {
  ch1 := make(chan bool, 1)
  c1, c2, c3, c4, c5 := 0, 0, 0, 0, 0

  func() {
    defer func() {
      fmt.Println(c1, c2, c3, c4, c5)
    }()

    for {
      fmt.Println("start")
      select {
      case ch1 <- callMe("c1"):
        c1++
        fmt.Println("in case1")
      case ch1 <- callMe("c2"):
        c2++
        fmt.Println("in case2")
      case ch1 <- callMe("c3"):
        c3++
        fmt.Println("in case3")
      case ch1 <- callMe("c4"):
        c4++
        fmt.Println("in case4")
      case ch1 <- callMe("c5"):
        c5++
        fmt.Println("in case5")
      }
      fmt.Println("end")
      <-ch1
      if c1+c2+c3+c4+c5 >= 100 {
        return
      }
    }
  }()
}

func callMe(s string) bool {
  fmt.Println("in", s)
  return true
}

每次跑完的結果都會不同,下面列出跑3次的結果

Result:
引用
23 18 17 30 12
21 18 18 24 19
26 11 20 25 18

http://play.golang.org/p/ky75RbvoEz

11
程式討論版 / [Golang] built-in function copy
« 於: 2015-09-06 00:17 »
Go 的內建函數,針對 slice 做資料複製,類似 c 的 memcpy

原型:

代碼: [選擇]
func copy(dst, src []Type) int
如果成功複製會傳回複製的個數

dst src 可以在同一個 slice 內操作

dst src 可以指定開始與結束的位置

代碼: [選擇]
copy(a1[5:6], a1[8:])
/*
result: a1: [1 3 5 7 9 19 13]
src 指定要複製8開始到最後,但是 dst 指定只能複製到第5的位置,因此只有複製 19 過來
*/

copy 常用在移除元素(remove elements)
下面註解的部分是在同一個 slice 操作
a3 則是建立新的 slice 存放結果

Code:
代碼: [選擇]
  a1 := []int{1, 3, 5, 7, 9, 11, 13, 17, 19, 23}
  a2 := make([]int, 15, 30)
  fmt.Println("a1:", a1)
  fmt.Println("a2:", a2)

  copy(a2[10:], a1)
  fmt.Println("a2:", a2)

  //remove 11, 13, 17
  //copy(a1[5:], a1[8:])
  //a1 = a1[:7]
 
  a3 := make([]int, 7)
  copy(a3[:5], a1)
  copy(a3[5:], a1[8:])
  fmt.Println("a3:", a3)


Result:
引用
a1: [1 3 5 7 9 11 13 17 19 23]
a2: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
a2: [0 0 0 0 0 0 0 0 0 0 1 3 5 7 9]
a3: [1 3 5 7 9 19 23]

http://play.golang.org/p/6MQcr5lu7t

12
go 有提供關閉 channel 的函數: close(ch)
在讀取時可以多一個變數取得 channel 的狀態

例如:

代碼: [選擇]
msg, ok := <- ch1
if ok {
  println(msg)
}

這樣可以避免去讀取一個已關閉的 channel
但奇怪的是,go 卻未提供判斷 channel 是否已關閉的功能
例如類似這樣的函數:

isClosed(ch1)

基於常久以來的習慣,總是會想在寫入前先做判斷
一直到目前的 1.5rc1 版,都還沒有這樣的函數
不過還有是其它方式可做到類似效果
只是不用 close(ch)
直接將這個 channel 設為 nil


代碼: [選擇]
package main

import (
  "fmt"
  "math/rand"
  "time"
)

const funcNum, gCountMax int = 20, 360

func main() {
  rand.Seed(time.Now().UTC().UnixNano())
  ch1, ch2 := make(chan string), make(chan string)

  for idx := 0; idx < funcNum; idx++ {
    go func(fid int) {
      fCount := 0
      for {
        if ch1 != nil {
          ch1 <- fmt.Sprintf(" [%v]: %v ", fid, fCount)
          fCount++
          if fCount > 18 {
            ch1 = nil
          }
          time.Sleep(time.Millisecond * time.Duration(rand.Intn(30)*5))
        } else {
          return
        }
      }
    }(idx)
  }

  gCount := 0
  rCount := 0
  go func() {
    defer func() { ch2 <- "Done!" }()
    for {
      select {
      case msg, ok := <-ch1:
        if ok {
          print(msg)
          rCount++
        }
        gCount++
        if gCount >= gCountMax {
          ch1 = nil
        }
      default:
        if ch1 == nil {
          return
        }
      }
    }
  }()
  msg := <-ch2
  fmt.Printf("\n%v, %s\n", rCount, msg)
}


if ch1 != nil {
  ch1 <- fmt.Sprintf(" [%v]: %v ", fid, fCount)
  .....

這邊在寫入 channel 前先判斷是否為 nil
當然,就不要再用 close() 關閉 channel


13
程式討論版 / [Golang] Wait for the goroutine end
« 於: 2015-08-11 19:25 »
goroutine 有個現象,在 main() 建立 goroutine 後,如果這個函數還沒跑完,
main() 並不會等它結束後才結束整個程式,看個例子

代碼: [選擇]
package main

func main() {
var count int64 = 0
go func() {
for idx := 0; idx < 200; idx++ {
count++
}
}()

println(count)
}

執行結果:

引用
$ go run ex041.go
0

for 迴圈根本就還沒跑到,整個程式就 game over
整理了幾個能讓 goroutine 確實跑完的方式

(1) 利用鍵盤輸入等待

代碼: [選擇]
import (
"fmt"
)

func main() {
var count int64 = 0
go func() {
for idx := 0; idx < 200; idx++ {
count++
}
}()

var in string
fmt.Scanln(&in)
println(count)
}

引用
result:
200

雖然可行,不過迴圈如果要跑很久,會因為按鍵盤時間快慢,迴圈也有可能不會完全跑完


(2) 利用 channel

代碼: [選擇]
func main() {
var count int64 = 0
c1 := make(chan bool)

go func() {
for idx := 0; idx < 200; idx++ {
count++
}
c1 <- true
}()
<-c1
println(count)
}

channel 型態不定要 bool,任何資料型態都可以,整數、字串甚至 struct 也可以

代碼: [選擇]
type MyType struct {
ID   int64
Name string
}

func main() {
var count int64 = 0
c1 := make(chan MyType)

go func() {
for idx := 0; idx < 200; idx++ {
count++
}
c1 <- MyType{}
}()
<-c1
println(count)
}

c1 目的只是要在接收資料時的等待效果。


(3) 使用 sync/WaitGroup

代碼: [選擇]
import (
"sync"
)

func main() {
var count int64 = 0
var wg sync.WaitGroup

wg.Add(1)
go func() {
defer wg.Done()
for idx := 0; idx < 200; idx++ {
count++
}

}()
wg.Wait()
println(count)
}

這個就比較清楚了,在使用 go 之前先告訴系統有一個 goroutine 要等待它跑完

defer wg.Done() 這行是告訴系統『我跑完嘍』

方式 1,2 適合單一 goroutine 或是數量不多時,當 goroutine 數量很多
sync/WaitGroup 就很好用,wg.Wait()會等到所有 goroutine 都結束才放行



14
程式討論版 / [Golang] Test & Benchmark 的寫法
« 於: 2015-08-10 17:39 »
go 提供的 test 與 benchmark 有3個限制,必需要依照這3個規則來做,這2兩個功能才跑得出來

1. 原始碼檔名必須以『 _b_test.go 』結尾,例如 getData_b_test.go

2. 測試的函數名必須 Test 或 Benchmark 開頭,至於之後的底線則可有可無,例如

   func TestgetData1(t *testing.T) {}
   func Test_getData1(t *testing.T) {}
   func BenchmarkgetData1(b *testing.B) {}
   func Benchmark_getData1(b *testing.B) {}

3. 如果要測試整個資料夾內的原始碼,則此資料夾的原始碼不能包含有任何的 main() 函數
   如果資料夾裡有 main() 則可改用單一檔案測試

假設現在要開發一個字串串接的功能,go 有3種方式可以串接字串
於是我們寫個測試碼來看看哪一種效率較高

src/strconcat/strconcat.go
(這個是我新開發的功能,不是測試碼,所以檔名不用加 _b_test)

代碼: [選擇]
package strconcat

import (
  "bytes"
)

func Strconcat1(str1, str2 string) string {
  return str1 + str2
}

func Strconcat12(str1, str2 string) {
  str1 += str2
}

func Strconcat13(str1, str2 string, str0 *string) {
  *str0 = str1 + str2
}

func Strconcat2(str1, str2 string, str0 *[]byte) {
  *str0 = []byte(str1)
  *str0 = append(*str0, str2...)
}

func Strconcat3(str1, str2 string, str0 *bytes.Buffer) {
  str0.WriteString(str1)
  str0.WriteString(str2)
}

接下來就要寫一個測試碼來跑這幾個函數

strconcat_b_test.go
(這個測試碼我放在目前工作資料夾內,不需要放在 src 裡)

代碼: [選擇]
package bmStrConcat

import (
  "bytes"
  "fmt"
  "testing"
  "strconcat"
)

var str1 string = "123456789012345678901234567890"
var str2 string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

func TestStrConcat1(t *testing.T) {
  str := strconcat.Strconcat1(str1, str2)
  if str != "" {
    fmt.Println(str)
  }
}

func TestStrConcat13(t *testing.T) {
  str := ""
  strconcat.Strconcat13(str1, str2, &str)
  if str != "" {
    fmt.Println(str)
  }
}

func TestStrConcat2(t *testing.T) {
  var str []byte
  strconcat.Strconcat2(str1, str2, &str)
  if string(str) != "" {
    fmt.Println(string(str))
  }
}

func TestStrConcat3(t *testing.T) {
  var str bytes.Buffer
  strconcat.Strconcat3(str1, str2, &str)
  if str.Len() >0 {
    fmt.Println(str.String())
  }
}

func BenchmarkStrConcat1(b *testing.B) {
  str0 := ""
  for idx := 0; idx < b.N; idx++ {
    str0 = strconcat.Strconcat1(str1, str2)
  }
  fmt.Sprintf("%v", str0)
}

func BenchmarkStrConcat12(b *testing.B) {
  for idx := 0; idx < b.N; idx++ {
    strconcat.Strconcat12(str1, str2)
  }
}

func BenchmarkStrConcat13(b *testing.B) {
  str0 := ""
  for idx := 0; idx < b.N; idx++ {
    strconcat.Strconcat13(str1, str2, &str0)
  }
}

func BenchmarkStrConcat2(b *testing.B) {
  var str0 []byte
  for idx := 0; idx < b.N; idx++ {
    strconcat.Strconcat2(str1, str2, &str0)
  }
}

func BenchmarkStrConcat3(b *testing.B) {
  var str0 bytes.Buffer
  for idx := 0; idx < b.N; idx++ {
    str0.Reset()
    strconcat.Strconcat3(str1, str2, &str0)
  }
}


Testxxxxx 的部分主要是查看新函數跑出來的結果是否正確
不一定要像上面那樣寫,也可以改成這樣

代碼: [選擇]
var str3 string = str1 + str2

func TestStrConcat1(t *testing.T) {
  str := strconcat.Strconcat1(str1, str2)
  if str != "" && str == str3 {
    fmt.Println("1 OK!")
  }
}

func TestStrConcat13(t *testing.T) {
  str := ""
  strconcat.Strconcat13(str1, str2, &str)
  if str != "" && str == str3 {
    fmt.Println("13 OK!")
  }
}

func TestStrConcat2(t *testing.T) {
  var str []byte
  strconcat.Strconcat2(str1, str2, &str)
  if string(str) == str3 {
    fmt.Println("2 OK!")
  }
}

func TestStrConcat3(t *testing.T) {
  var str bytes.Buffer
  strconcat.Strconcat3(str1, str2, &str)
  if str.String() == str3 {
    fmt.Println("3 OK!")
  }
}


Benchmark 的部分就是用迴圈去呼叫新函數...

執行方式跟原來差不多,只是 run 改成 test,並加個選項

引用
$ go test strconcat_b_test.go -bench=.
1 OK!
13 OK!
2 OK!
3 OK!
PASS
BenchmarkStrConcat1-4    10000000          205 ns/op
BenchmarkStrConcat12-4   10000000          218 ns/op
BenchmarkStrConcat13-4   10000000          225 ns/op
BenchmarkStrConcat2-4     5000000          331 ns/op
BenchmarkStrConcat3-4    30000000           56.4 ns/op
ok     command-line-arguments   10.918s

-bench=. 表示測試所有的 Textxxx() 與 Benchmarkxxx()

有時候只想看某部分的結果,例如只跑 StrConcat3 的部分,指令可以這樣下

引用
$ go test strconcat_b_test.go -run=.*t3 -bench=.*t3
3 OK!
PASS
BenchmarkStrConcat3-4   30000000           52.4 ns/op
ok     command-line-arguments   1.642s

跑 StrConcat2 跟 StrConcat3 的話

引用
$ go test strconcat_b_test.go -run=.*t[23] -bench=.*t[23]
2 OK!
3 OK!
PASS
BenchmarkStrConcat2-4    5000000          315 ns/op
BenchmarkStrConcat3-4   30000000           52.4 ns/op
ok     command-line-arguments   3.551s

或是跑 1,3

引用
$ go test strconcat_b_test.go -run=.*t[13] -bench=.*t[13]
1 OK!
13 OK!
3 OK!
PASS
BenchmarkStrConcat1-4    10000000          200 ns/op
BenchmarkStrConcat12-4   10000000          190 ns/op
BenchmarkStrConcat13-4   10000000          199 ns/op
BenchmarkStrConcat3-4    30000000           51.7 ns/op
ok     command-line-arguments   8.193s

or

引用
$ go test strconcat_b_test.go -run=.*t[13]$ -bench=.*t[13]$
1 OK!
3 OK!
PASS
BenchmarkStrConcat1-4   10000000          199 ns/op
BenchmarkStrConcat3-4   30000000           52.1 ns/op
ok     command-line-arguments   3.834s

t[13]$ 表示結尾,所以 strconcat12, strconcat13 就不會跑


有人說,自己寫 package 之後一定要加 test 的碼
其實看個人啦,如果是要公開給大家用的,那當然就需要囉
最好連 benchmark 的部分都直接提供
如果只是自己用,那就看自己嚕!^_____^




15
程式討論版 / [Golang] channel & for & select
« 於: 2015-08-06 18:15 »
今天看了這篇

Golang channels tutorial

算是這兩週所看過相關文章中,對 channel 使用有比較簡單清楚的說明

不過很可惜最後還是少了一種情況,就是當 channel 需要發送的資料數不確定時
文章最後範例是這樣:

代碼: [選擇]
package main

import (
"fmt"
"time"
)

func getMesgChannel(msg string, delay time.Duration) <-chan string {
c := make(chan string)
go func() {
for i := 1; i <= 3; i++ {
c <- fmt.Sprintf("%s, %d", msg, i)
time.Sleep(time.Millisecond * delay)
}
}()
return c
}

func main() {
c1 := getMesgChannel("001", 300)
c2 := getMesgChannel("002", 150)
c3 := getMesgChannel("003", 10)

for i := 1; i <= 9; i++ {
select {
case msg := <-c1:
fmt.Println(msg)
case msg := <-c2:
fmt.Println(msg)
case msg := <-c3:
fmt.Println(msg)
}
}
}

實際上在很多場合,如果 sender 不確定會發送多少資料出來
在接收端通常會用無窮迴圈來接收資料,例如:

代碼: [選擇]
  for {
select {
.....
}
}

但是這真的會造成無窮迴圈啊,發送端如果都停止送資料

fatal error: all goroutines are asleep - deadlock!

在 getMesgChannel() for{} 結束時關閉 channel 呢?
很可惜,一樣會造成 deadlock

我自己想到的方式是在 select 加一條 time.After的 case
超過多久時間沒收到任何訊息便結束迴圈

代碼: [選擇]
  for {
select {
case msg := <-c1:
fmt.Println(msg)
case msg := <-c2:
fmt.Println(msg)
case msg := <-c3:
fmt.Println(msg)
case <-time.After(time.Millisecond * 500):
fmt.Println("Done!")
break
}
}

不過這裡的 break 只會對 select 區塊有作用
還是無法跳出 for 迴圈,結果就是一直印出『Done!』

有兩個方式可以跳出 for 迴圈,一個是設變數來判斷
另一個是將 break 改成 return

代碼: [選擇]
  done := false
for {
select {
    ..... 
case <-time.After(time.Millisecond * 500):
fmt.Println("Done!")
return
done = true
}
if done {
break
}
}

or
代碼: [選擇]
    case <-time.After(time.Millisecond * 500):
fmt.Println("Done!")
return
完整範例:

或點這裡

代碼: [選擇]
package main

import (
"fmt"
"time"
)

func getMesgChannel(msg string, count int, delay time.Duration) <-chan string {
c := make(chan string)
go func() {
for i := 1; i <= count; i++ {
c <- fmt.Sprintf("%s, %d", msg, i)
time.Sleep(time.Millisecond * delay)
}
}()
return c
}

func main() {
c1 := getMesgChannel("001", 5, 300)
c2 := getMesgChannel("002", 8, 200)
c3 := getMesgChannel("003", 13, 10)

done := false
for {
select {
case msg := <-c1:
fmt.Println(msg)
case msg := <-c2:
fmt.Println(msg)
case msg := <-c3:
fmt.Println(msg)
case <-time.After(time.Millisecond * 500):
fmt.Println("Done!")
      done = true
//return
}
if done {
break
}
}
}

執行結果:

引用
$ time go run ex038.go
002, 1
003, 1
001, 1
003, 2
003, 3
003, 4
003, 5
003, 6
003, 7
003, 8
003, 9
003, 10
003, 11
003, 12
003, 13
002, 2
001, 2
002, 3
002, 4
001, 3
002, 5
001, 4
002, 6
002, 7
001, 5
002, 8
Done!

real   0m2.411s
user   0m0.552s
sys   0m0.284s


16
在語法上, goroutine 不能有傳回值,或者換個比較正確的說法
在 『go func()』這個述中,不能有等號出現,所以就算函數有傳回值
在函數結束後返回的值會直接被丟棄

代碼: [選擇]
import (
"fmt"
)

func getInt() int {
return 12345
}

func main() {
res := 0
go res = getInt()
fmt.Println(“res:”, res)

}
 

這裡編譯就過不了

引用
$ go run ex032.go
# command-line-arguments
./ex032.go:12: syntax error: unexpected =, expecting ( or . or [

但是有傳回值並不會不給『go』

代碼: [選擇]
func main() {
go getInt()
fmt.Println("Done!")

}

就算函數有傳回值,其實還是可以『go』
只是無法接收傳回值,直接忽略了

引用
$ go run ex032.go
Done!

如果無論如何,一定要得到那個傳回值呢?!
那就改用 channel 來傳吧

代碼: [選擇]
func getInt(c chan int) {
c <- 12345
}

func main() {
c := make(chan int)
go getInt(c)
res := <-c
fmt.Println("res:", res)
}

引用
$ go run ex032.go
res: 12345

^_____^

17
早上在修改一些 c++ 的東西,發現一個有趣的現象

下面是測試碼:

代碼: [選擇]
#include <iostream>
#include "microtime.h"

void swap(int &x, int &y) {
int tmp(x);
x = y;
y = tmp;
}

const int loopMax = 50000001;

int main() {
  int x = 24578, y = 2982;
  double t1 = microtime();
  for (int idx=0; idx<loopMax; ++idx) {
    swap(x, y);
  }
  t1 = microtime(t1);
  std::cout << "x, y = " << x << ", " << y
            << " [" << t1*1000 << "ms]\n";

  return 0;
}


本來是用 clang++ -O3 編譯,發現跑出來的時間怪怪的
於是就加 -S 看一下編出來的 asm code

代碼: [選擇]
fdivs .LCPI1_0(%rip)
    movl $50000002, %ecx         # imm = 0x2FAF082
    .align 16, 0x90
.LBB1_1:                                # =>This Inner Loop Header: Depth=1
    addl $-26, %ecx
    jne .LBB1_1
# BB#2:

哈~~~~~ 原來是騙局啦~~~
迴圈數還會偷偷加1呢~ ^_^

然後 cout 的地方
就直接將編譯器預估的結果印出來

 
代碼: [選擇]
    movl $2982, %esi             # imm = 0xBA6
    callq _ZNSolsEi
    movq %rax, %rbx
    movl $.L.str1, %esi
    movl $2, %edx
    movq %rbx, %rdi
    callq _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
    movl $24578, %esi            # imm = 0x6002
    movq %rbx, %rdi
    callq _ZNSolsEi

所以根本就沒有真的跑 swap
連迴圈也是偷工減料來跑 XD

後來我改用 -O1 來編譯看看,另外也用 g++ 編

clang -O1:
 
代碼: [選擇]
    movl $50000001, %ebp         # imm = 0x2FAF081
    callq _Z9microtimee
    fstpt 16(%rsp)                # 10-byte Folded Spill
    leaq 60(%rsp), %r14
    leaq 56(%rsp), %rbx
    .align 16, 0x90
.LBB2_1:                                # =>This Inner Loop Header: Depth=1
    movq %r14, %rdi
    movq %rbx, %rsi
    callq _Z4swapRiS_
    decl %ebp
    jne .LBB2_1
# BB#2:

clang -O1 就有正常跑迴圈和呼叫 swap()
不過卻沒有自動將 swap() 編成 inline


g++ -O1:
代碼: [選擇]
    movl $50000001, %eax
    movl $24578, %ebx
    movl $2982, %ebp
    jmp .L12
.L13:
    movl %ebp, %edx
    movl %ebx, %ebp
    movl %edx, %ebx
.L12:
    subl $1, %eax
    jne .L13
   
.L13 ~ .L12 之間這3行就是實際執行 swap() 的動作

g++ -O3:
代碼: [選擇]
    movl $50000001, %eax
    fldl 40(%rsp)
    popq %rcx
    .c 72
    popq %rsi
    .cfi_def_cfa_offset 64
    jmp .L14
    .p2align 4,,10
    .p2align 3
.L15:
    movl %ebp, %edx
    movl %ebx, %ebp
    movl %edx, %ebx
.L14:
    subl $1, %eax
    jne .L15

swap() 的動作是在 .L15 ~ .L14

g++ -O1 或 -O3 都會正常編出迴圈
而且也會自動將 swap 編成 inline

下面是跑出來的結果

引用
$ ./ex044-clang++O1 && ./ex044-clang++O3 && ./ex044-g++O1 && ./ex044-g++O3
x, y = 2982, 24578 [1081.17ms]
x, y = 2982, 24578 [3.09399ms]
x, y = 2982, 24578 [402.601ms]
x, y = 2982, 24578 [339.092ms]

g++ 將 swap() 編成 inline
執行時就減少函數呼叫動作
因此會比 clang++ -O1 的碼快


18
php 用習慣了,換個語言來開發總是會想說最好也能夠有支援類似 php 的 hash table
還好 golang 雖然沒有直接支援,不過可以很簡單地定義一個類似的型態來用
例如:

代碼: [選擇]
<?php
error_reporting(0);

$mVal1["k01"] = 12345;
$mVal1["k02"] = "abcdefg";
$mVal1["k03"]["k31"] = 54321;
$mVal1["k03"]["k32"] = "資料123";

var_dump($mVal1);
echo "\$mVal1['k04']['k41']: {$mVal1['k04']['k41']}\n";
?>

在 golang 可以這樣來用

代碼: [選擇]
package main

import (
"fmt"
)

type hash map[string]interface{}

func main() {
mVal1 := make(hash)

mVal1["k01"] = 12345
mVal1["k02"] = "abcdefg"
mVal1["k03"] = make(hash)
mVal1["k03"].(hash)["k31"] = 54321
mVal1["k03"].(hash)["k32"] = "資料123"

fmt.Println("mVal1:", mVal1)
fmt.Println("mVal1[k01]:", mVal1["k01"])
fmt.Println("mVal1[k03]:", mVal1["k03"])
fmt.Println("mVal1[k03][k32]:", mVal1["k03"].(hash)["k32"])
fmt.Println("mVal1[k03][k33]:", mVal1["k03"].(hash)["k33"])

  fmt.Println("mVal1[k04][k42]:", mVal1["k04"].(hash)["k42"])
}

hash 這個自己定義的型態在使用上就有類似 php 陣列的效果
不過,不小心用到未定義過的 key 就掛掉了,像這樣

引用
$ go run ex030.go
mVal1: map[k01:12345 k02:abcdefg k03:map[k31:54321 k32:資料123]]
mVal1[k01]: 12345
mVal1[k03]: map[k31:54321 k32:資料123]
mVal1[k03][k32]: 資料123
mVal1[k03][k33]: <nil>
panic: interface conversion: interface is nil, not main.hash

goroutine 1 [running]:
main.main()
   /home/cpp/go/ex030.go:25 +0xcfe

golang 不會像 php 那樣,使用未定義過的變數就直接空白跳過

雖然麻煩,不過還是有解法:
 
代碼: [選擇]
  //fmt.Println("mVal1[k04][k42]:", mVal1["k04"].(hash)["k42"])
 
  if k04, ok := mVal1["k04"]; ok {
fmt.Println("mVal1[k04][k42]:", mVal1["k04"].(hash)["k42"])
fmt.Println("k04.[k41]", k04.(hash)["k41"])
} else {
mVal1["k04"] = make(hash)
mVal1["k04"].(hash)["k42"] = "新增資料567"
    fmt.Println("mVal1[k04][k41]:", mVal1["k04"].(hash)["k41"])
fmt.Println("mVal1[k04][k42]:", mVal1["k04"].(hash)["k42"])
}

引用
$ go run ex030.go
mVal1: map[k01:12345 k02:abcdefg k03:map[k32:資料123 k31:54321]]
mVal1[k01]: 12345
mVal1[k03]: map[k31:54321 k32:資料123]
mVal1[k03][k32]: 資料123
mVal1[k03][k33]: <nil>
mVal1[k04][k41]: <nil>
mVal1[k04][k42]: 新增資料567

---
在用 json 字串 decode 轉成 map 後就要很小心使用這個 map
不然碰到沒有預期中該有的 key 就會像上面那樣掛了
^__________^

19
因為剛好看到 go1.5b2 已完成 9x%,想說就抓下來試一下
意外發現 1.5b2 編出來的碼執行效能真的快了不少
這是我原來用的測試碼:

代碼: [選擇]
package main

import (
"fmt"
"sync"
"runtime"
)

const loopMax = 100000
var wg sync.WaitGroup
var goCount, allDone int64 = 0, 0
var c chan bool = make(chan bool, 1)

func addCount() {
defer wg.Done()
for ok := range c  {
if ok {
goCount++
}
if allDone == 0 {
close(c)
}
}
}

func func1(id int) {
defer wg.Done();
//defer close(c)
var str1, str2 string = "在資料序列(Data sequence)中隨機找一元素為定界點(Pivot)," +
"然後讓序列的其他元素與定界點比較,比定界點小的元素放左邊,大的放右邊。在定界點左邊子序列" +
"和右邊子序列,再以相同的方式處理,直到整個序列排序完畢。", ""

for idx:=0; idx<loopMax; idx++ {
str2 = fmt.Sprintf("[%v]%v", id, str1)
c <- true
}
allDone--
fmt.Println(str2)
}

func main() {
//runtime.GOMAXPROCS(2)
runtime.GOMAXPROCS(runtime.NumCPU())

allDone = 4

for idx:=0; idx<4; idx++ {
wg.Add(1)
go func1(idx)
}

defer func() {
fmt.Println(goCount)
}()

wg.Add(1)
go addCount()
wg.Wait()
}

開4個 goroutine 加 4核心來跑,結果如下

引用
$ go version
go version go1.4.2 linux/amd64
$ go build -o ex022-01 ex022.go

$ go version
go version go1.5beta2 linux/amd64
$ go build -o ex022-02 ex022.go

$ time ./ex022-01 && time ./ex022-02
[3]在資料序列(Data sequence)中隨機找一元素為定界點(Pivot),然後讓序.....
[2]在資料序列(Data sequence)中隨機找一元素為定界點(Pivot),然後讓序.....
[1]在資料序列(Data sequence)中隨機找一元素為定界點(Pivot),然後讓序.....
[ 0 ]在資料序列(Data sequence)中隨機找一元素為定界點(Pivot),然後讓序.....
400000

real   0m3.922s
user   0m4.379s
sys   0m5.404s
[3]在資料序列(Data sequence)中隨機找一元素為定界點(Pivot),然後讓序.....
[2]在資料序列(Data sequence)中隨機找一元素為定界點(Pivot),然後讓序.....
[1]在資料序列(Data sequence)中隨機找一元素為定界點(Pivot),然後讓序.....
[ 0 ]在資料序列(Data sequence)中隨機找一元素為定界點(Pivot),然後讓序.....
400000

real   0m1.258s
user   0m1.466s
sys   0m0.496s

其實本來是沒有用到 fmt.Sprintf(),加了這個函數後發現差更多

另外我把前兩天玩的碼也拿測了一下,是 json 的編碼與解碼


代碼: [選擇]
package main
import (
"fmt"
"yHash"
)

func main() {
var vecVal1 [5]int = [5]int{1, 2, 3, 4, 5} // array
var vecVal2 []int = []int{1, 2, 3, 4, 5} // slice

hash1 := make(yHash.Hash)

hash1["abc"] = 12345
hash1["def"] = "abcdefghijk"
hash1["vec1"] = vecVal1
hash1["vec2"] = vecVal2
//hash1["subHash"] = make(yHash.Hash)
hash1["subHash"] = yHash.Hash {
"編號1": "9456234534254",
"編號2": 9456234534254,
"編號3": 9456234,
"編號4": 945623,
"單位":  "研發",
"專長1": yHash.Hash{
"第一": "吃飯",
"第二": "睡覺",
"第三": "玩電動",
"第四": "看動漫",
},
}

hash1["subHash"].(yHash.Hash)["專長2"] = yHash.Hash{
"S01" : "C++",
"S02" : "PHP",
"S03" : "Java",
"S04" : "Perl",
"S05" : "Golang",
"S06" : "Python",
"S07" : "ShellScript",
"S08" : "JavaScript",
"S09" : "HTML/CSS",
"S10" : "Pascal",
}

fmt.Println(hash1)
fmt.Println(hash1["subHash"].(yHash.Hash)["專長1"].(yHash.Hash)["第一"])

var loopMax int = 100000
var tDatas string
for idx:=0; idx<loopMax; idx++ {
tDatas = hash1.JsonEncode()
}

fmt.Println(tDatas)
fmt.Println("\nEncode OK!\n")

var hash2 yHash.Hash
for idx:=0; idx<loopMax; idx++ {
hash2.JsonDecode(tDatas)
}
fmt.Println("Decode OK!\n")

id21, ok := hash2["subHash"].(map[string] interface{})["編號2"]
var id22 int64
if ok {
id22 = yHash.GetJsonInt(id21)
hash2["subHash"].(map[string] interface{})["編號2"] = id22
}
hash2["subHash"].(map[string] interface{})["編碼"] = 238462.1238478349
fmt.Println(hash1, "\n\n", id21, id22)
fmt.Printf("\n%v\n", hash2)

hash1.Dump()
hash2.Dump()
}


引用
$ time ./ex020-01 && time ./ex020-02
.....

real   0m10.971s
user   0m12.318s
sys   0m3.005s

.....

real   0m8.012s
user   0m9.383s
sys   0m2.916s

跑出來結果 1.5b2 也快了不少!!

---
也許真的有那麼一天
當 golang 與 c++ 執行速度並駕齊驅時.....
^_____________^

20
記得之前好像有開啟限定連續發文時間啊

最近真的好多洗版廣告  =___________=|||

21
今天在玩 Go 解 Sqrt() 碰到一個問題(今天第一次玩 Go,有誤請指正 ^__^)

Code:
代碼: [選擇]
package main
import (
  "fmt"
  "math"
)

var step int = 0;
var z float64 = 1.0;
var s float64 = 0.0;

func Sqrt(x float64) float64 {
  if step >= 12 {
    return x
  }
 
  if s == 0 {
    s = x
  }
 
  z = (z + s/z) / 2
  step++
  fmt.Println(z, x, step)
  Sqrt(z)
  return z
}

func main() {
  x := 12345.0;
 
  fmt.Println("Sqrt:");
  fmt.Println(Sqrt(x), "\n");

  fmt.Println(math.Sqrt(x));
}

Result:
引用
Sqrt:
6173 12345 1
3087.499919002106 6173 2
1545.7491498369006 3087.499919002106 3
776.8677842956971 1545.7491498369006 4
396.37925958974336 776.8677842956971 5
213.76183709549736 396.37925958974336 6
135.75651245108165 213.76183709549736 7
113.34568823712989 135.75651245108165 8
111.13014281250861 113.34568823712989 9
111.10805770848404 111.13014281250861 10
111.10805551354053 111.10805770848404 11
111.1080555135405 111.10805551354053 12
111.1080555135405

111.1080555135405

---
雖然有弄出來,只是有一點很不滿意,就是 Go 竟然未支援靜態變數!!!
所以上面有三個變數要宣告為全域變數,這樣真的很危險啊!!

後來看到有支援 closure 功能,於是就試了一下改成如下

Code:
代碼: [選擇]
func Sqrt2(x float64) float64 {
  step := 0;
  z := 1.0;
  s := x;
  var Sqrt func(float64) float64
 
  Sqrt = func(x float64) float64 {
    if step >= 12 {
      return x
    }
   
    z = (z + s/z) / 2
    step++
    fmt.Println(z, x, step)
    Sqrt(z)
    return z
  }
 
  return Sqrt(s);
}

func main() {
  x := 12345.0;
 
  fmt.Println("Sqrt:");
  fmt.Println(Sqrt(x), "\n");
 
  fmt.Println("Sqrt2:");
  fmt.Println(Sqrt2(x), "\n");
 
  fmt.Println(math.Sqrt(x));
}

Result:
引用
Sqrt2:
6173 12345 1
3087.499919002106 6173 2
1545.7491498369006 3087.499919002106 3
776.8677842956971 1545.7491498369006 4
396.37925958974336 776.8677842956971 5
213.76183709549736 396.37925958974336 6
135.75651245108165 213.76183709549736 7
113.34568823712989 135.75651245108165 8
111.13014281250861 113.34568823712989 9
111.10805770848404 111.13014281250861 10
111.10805551354053 111.10805770848404 11
111.1080555135405 111.10805551354053 12
111.1080555135405

這樣就可以將原來的全域變數改成區域變數
當然,執行結果完全相同 ^____^



22
平常都都是用不同帳號處理不同的事情
例如寫 java 程式用 jper,寫 c++ 程式用 cpp
本來也都只是寫一些非視窗模式的程式
最近因為要開發一些 GUI 的東西
又不想直接改用桌面這個帳號來寫
所以就想到 ssh 有這功能可用

工作系統為 ubuntu 14.10 + mate 桌面
基本上沒另外做什麼設定
openssh-server 本來就已安裝

確定一下 ssh server 的設定

代碼: [選擇]
$ sudo vim /etc/ssh/sshd_config

X11Forwarding yes
X11DisplayOffset 10

確認後就可以直接連線

$ ssh -X cpp@192.168.xx.xxx

或是

$ ssh -X jper@localhost

連線時只要多加一個『 -X 』就好
登入後可以查看一下環境變數

引用
$ echo $DISPLAY
localhost:11.0

我有另外改了一下 .bashrc 來分辨連線方式
用 -X 連線後看起來像這樣

jper@xub1410d(X11):~$

這樣可以用這個帳號的權限來開 GUI 程式

jper@xub1410d(X11):~$ eclipse&

結果如附圖





視窗標題列後面會顯示目前所使用的身分 (as jper)
在 eclipse 裡使用的家目錄也是 jper 的

這樣就可以繼續用不同的帳號工作 ^___^

PS: 哈~附圖傳不上來啦
(補上圖片了)

23
Linux 討論版 / ubuntu + zfs 設定記憶體使用量
« 於: 2015-06-12 12:34 »
昨天在 ubuntu 裝了 openzfs
用4顆硬碟建立 raid10
剛剛看了一下系統狀態
發現記憶體(15GB free)被吃光光
而且還吃到一點點 swap
我記得有 zfs 記憶使用量的設定
google 了一下,方式如下(限4GB)

引用
$ sudo sh -c 'echo "options zfs zfs_arc_max=4294967296" >> /etc/modprobe.d/zfs.conf'
$ sudo sh -c 'echo "4294967296" > /sys/module/zfs/parameters/zfs_arc_max'

(以下非必要)
引用
$ sudo sync
$ sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches'
$ sudo swapoff /dev/sdxx
$ sudo swapon /dev/sdxx

觀察了幾個小時,記憶體限制有作用
或許多少會影響 zfs 的效能
不過至少不會吃光 ram 或吃到 swap
^___^

24
本來是在 clang 編譯,想說試一下 g++ 是否有支援右值參考,編譯是會過,沒有任何警告或錯誤訊息
不過執行結果卻是大問題 @_____@||

測試碼如下:

代碼: [選擇]
#include <iostream>

int&& func(int&& x) {
  x *= 7;
  std::cout << x << " [&x: " << &x << "]\n";
  return std::move(x);
  // or
  //return static_cast<int&&>(x);
}

void func2(int&& y) {
  std::cout << y << " [&y: " << &y << "]\n";
}

int main() {
  int ival = 3;
  int *pival = &ival;

  int&& rival = func(ival+0);
  //int&& rival = func(std::move(ival));
  rival++;

  std::cout << ival << " [&ival: " << &ival << "]\n";
  std::cout << *pival << " [pival: " << pival << "]\n";
  std::cout << rival << " [&rival: " << &rival << "]\n";
  func2(func(5));
  std::cout << rival << " [&rival: " << &rival << "]\n";
 
  int&& rival2 = func(6);
  std::cout << rival << " [&rival: " << &rival << "]\n";
  std::cout << rival2 << " [&rival2: " << &rival2 << "]\n";
 
  int&& rival3 = func(7);
  std::cout << rival << " [&rival: " << &rival << "]\n";
  std::cout << rival2 << " [&rival2: " << &rival2 << "]\n";
  std::cout << rival3 << " [&rival3: " << &rival3 << "]\n";

  return 0;
}

先是 clang 的結果

引用
$ clang++ -v
Ubuntu clang version 3.5.0-4ubuntu2 (tags/RELEASE_350/final) (based on LLVM 3.5.0)
Target: x86_64-pc-linux-gnu
$ clang++ -O3 -std=c++11 ex015.cc -o ex015
$ ./ex015
21 [&x: 0x7ffc5b136540]
3 [&ival: 0x7ffc5b136544]
3 [pival: 0x7ffc5b136544]
22 [&rival: 0x7ffc5b136540]
35 [&x: 0x7ffc5b13653c]
35 [&y: 0x7ffc5b13653c]
22 [&rival: 0x7ffc5b136540]
42 [&x: 0x7ffc5b136538]
22 [&rival: 0x7ffc5b136540]
42 [&rival2: 0x7ffc5b136538]
49 [&x: 0x7ffc5b136534]
22 [&rival: 0x7ffc5b136540]
42 [&rival2: 0x7ffc5b136538]
49 [&rival3: 0x7ffc5b136534]

執行結果跟預期的一樣,右值參考功能有正常工作
改用 g++ 編譯也 OK(與 clang 同一系統環境)
只是執行結果就.....

引用
$ g++ -v
Target: x86_64-linux-gnu
gcc version 4.9.1 (Ubuntu 4.9.1-16ubuntu6)
$ g++ -O3 -std=c++11 ex015.cc -o ex015
$ ./ex015
21 [&x: 0x7ffce55d8ac4]
3 [&ival: 0x7ffce55d8ac0]
3 [pival: 0x7ffce55d8ac0]
22 [&rival: 0x7ffce55d8ac4]
35 [&x: 0x7ffce55d8ac4]
35 [&y: 0x7ffce55d8ac4]
35 [&rival: 0x7ffce55d8ac4]
42 [&x: 0x7ffce55d8ac4]
42 [&rival: 0x7ffce55d8ac4]
42 [&rival2: 0x7ffce55d8ac4]
49 [&x: 0x7ffce55d8ac4]
49 [&rival: 0x7ffce55d8ac4]
49 [&rival2: 0x7ffce55d8ac4]
49 [&rival3: 0x7ffce55d8ac4]

每次呼叫 func(),x 都會使用相同位址,所以 rival 的值一直都跟著改變
而且正常來說,每次呼叫 func() 時都應該是『配置』新的位置存放 x 值,
rival 與 rival2 指向的位址也就應該要不同

正好手邊有 vc++ 2012 express,順便也測試了一下(code 一樣)

引用
21 [&x: 003AFDDC]
3 [&ival: 003AFDE8]
3 [pival: 003AFDE8]
22 [&rival: 003AFDDC]
35 [&x: 003AFDE0]
35 [&y: 003AFDE0]
22 [&rival: 003AFDDC]
42 [&x: 003AFDE0]
22 [&rival: 003AFDDC]
42 [&rival2: 003AFDE0]
49 [&x: 003AFDE4]
22 [&rival: 003AFDDC]
42 [&rival2: 003AFDE0]
49 [&rival3: 003AFDE4]
請按任意鍵繼續 . . .

執行結果跟 clang 差不多,只差在傳回值最後如果未被參考(func2那裡)
則該位址會被重覆使用,雖然有些微差異,但並不影響執行結果


25
請問各位先進

如果有下面的情形

$ sudo zpool status
代碼: [選擇]
  pool: rpool
config:

        NAME        STATE     READ WRITE CKSUM
        rpool       DEGRADED     0     0     0
          raidz2-0  DEGRADED     0     0     2
            c4d1    DEGRADED     3     5    47  too many errors
            c6d0    ONLINE       0     0     1
            c6d1    ONLINE       0     0     0
            c7d0    DEGRADED     0    30   420  too many errors
            c7d1    DEGRADED    21     0    24  too many errors

errors: No known data errors


READ, WRITE, CKSUM 單純只是 zfs 系統問題
還是硬碟也真的有問題,例如壞軌之類的...
c7d0 拔到 linux 系統用 smartctl 看卻都 ok

$ sudo smartctl -AH /dev/sdb
代碼: [選擇]
smartctl 5.41 2011-06-09 r3365 [x86_64-linux-3.5.0-54-generic] (local build)
Copyright (C) 2002-11 by Bruce Allen, http://smartmontools.sourceforge.net

=== START OF READ SMART DATA SECTION ===
SMART overall-health self-assessment test result: PASSED

SMART Attributes Data Structure revision number: 16
Vendor Specific SMART Attributes with Thresholds:
ID# ATTRIBUTE_NAME          FLAG     VALUE WORST THRESH TYPE      UPDATED  WHEN_FAILED RAW_VALUE
  1 Raw_Read_Error_Rate     0x002f   200   200   051    Pre-fail  Always       -       0
  3 Spin_Up_Time            0x0027   177   176   021    Pre-fail  Always       -       6150
  4 Start_Stop_Count        0x0032   100   100   000    Old_age   Always       -       28
  5 Reallocated_Sector_Ct   0x0033   200   200   140    Pre-fail  Always       -       0
  7 Seek_Error_Rate         0x002e   200   200   000    Old_age   Always       -       0
  9 Power_On_Hours          0x0032   080   080   000    Old_age   Always       -       14740
 10 Spin_Retry_Count        0x0032   100   253   000    Old_age   Always       -       0
 11 Calibration_Retry_Count 0x0032   100   253   000    Old_age   Always       -       0
 12 Power_Cycle_Count       0x0032   100   100   000    Old_age   Always       -       28
192 Power-Off_Retract_Count 0x0032   200   200   000    Old_age   Always       -       27
193 Load_Cycle_Count        0x0032   200   200   000    Old_age   Always       -       0
194 Temperature_Celsius     0x0022   114   096   000    Old_age   Always       -       36
196 Reallocated_Event_Count 0x0032   200   200   000    Old_age   Always       -       0
197 Current_Pending_Sector  0x0032   200   200   000    Old_age   Always       -       0
198 Offline_Uncorrectable   0x0030   100   253   000    Old_age   Offline      -       0
199 UDMA_CRC_Error_Count    0x0032   200   200   000    Old_age   Always       -       0
200 Multi_Zone_Error_Rate   0x0008   100   253   000    Old_age   Offline      -       0

$ sudo badblocks -vs /dev/sdb
代碼: [選擇]
Checking blocks 0 to 1953514583
Checking for bad blocks (read-only test): done                                                 
Pass completed, 0 bad blocks found. (0/0/0 errors)

所以像上面這棵 /dev/sdb 這樣的資訊,就表示這棵 hdd 是『健康』的?


26
測試環境: ubuntu 12.04 + mate desktop 1.6

目標是要能在桌面的 terminal shell script 抓桌面上任意點的顏色值
有找到 grabc 套件(ubuntu可直接用 apt-get安裝),但是這個指令需要
用滑鼠點取要抓的點,不能直接提供座標資料來抓,這樣就不合需求了..

本來想抓 grabc 的原始碼來改,不過有點懶,而且不同環境又還得另外編譯
於是就想找看看有沒有用 perl 寫的,結果只找到 python 的版本...

http://stackoverflow.com/questions/1605350/how-can-i-grab-the-color-of-a-pixel-on-my-desktop-linux

這頁有兩種版本,下面的版本抓點速度有比較快

最近在用 perl 弄東西,所以就順便將它用 perl 改寫

代碼: [選擇]
$ cat grabc.pl

#!/usr/bin/perl -w

use strict;
use warnings;
use Gtk2 '-init';

my ($x, $y, $fmt) = @ARGV;

die "Usage: grabc x y [d]\nd: result decimal, default hex.\n" if !defined($x) || !defined($y);

my $rootW = Gtk2::Gdk->get_default_root_window();
my $pixbuf = Gtk2::Gdk::Pixbuf->new('rgb', 0, 8, 1, 1);
$pixbuf->get_from_drawable($rootW, $rootW->get_colormap(), $x, $y, 0, 0, 1, 1);
my @pixels = $pixbuf->get_pixels();
$fmt = $fmt && lc($fmt) eq 'd';
my @rgb = unpack(($fmt ? 'C*' : 'H*'), $pixels[0]);
print(($fmt?'':'#'), substr(join(' ', @rgb), 0, ($fmt?-1:-2)), "\n");

加執行權限

代碼: [選擇]
$ chmod +x grabc.pl

$ ./grabc.pl 621 10
#3ae292

or

$ ./grabc.pl 621 10 d
58 226 146

常常用到的話,cp 到環境路下比較方便

代碼: [選擇]
$ sudo cp grabc.pl /usr/local/bin/grabc
$ ls -l /usr/local/bin/grabc
-rwxr-xr-x 1 root root 862 Jul 31 15:55 /usr/local/bin/grabc

$ grabc
Usage: grabc x y [d]
d: result decimal, default hex.

另外我有時會用其他身分操作, 試過將 /usr/local/bin/grabc 改 owner 並加上 SUID
不過其他身分還是沒法直接使用

代碼: [選擇]
$ sudo su xxxxx
$ grabc
No protocol specified
No protocol specified
Gtk-WARNING **: cannot open display: :0 at /usr/lib/perl5/Gtk2.pm line 138.

如果加 sudo 就OK了

代碼: [選擇]
$ sudo grabc 123 123 d
237 236 235

27
system: ubuntu 14.04 server x64 + php 5.5.9

這次是在編譯 php_cconv 這支程式時出現錯誤訊息

代碼: [選擇]
$ sudo make
.....

/usr/local/src/cconv-php-0.6.4/php_cconv.c:10:1: error: unknown type name 'function_entry'
 static function_entry cconv_functions[] = {
 ^
.....
make: *** [php_cconv.lo] Error 1

之前在 ubuntu 12.04 + php 5.3.10 環境下編譯沒問題啊
於是就抓 php 原始碼來編看看,因為之前我有編過 pdo
這次也試試編 pdo

代碼: [選擇]
$ cd /tmp
$ wget http://tw1.php.net/distributions/php-5.5.14.tar.gz
$ cd /usr/local/src
$ sudo tar zxf /tmp/php-5.5.14.tar.gz
$ cd php-5.5.14/ext/pdo
$ sudo phpize
$ sudo ./configure --with-php-config=/usr/bin/php-config
$ sudo make
.....

Build complete.
Don't forget to run 'make test'.

$ ls -l modules
total 436
-rw-r--r-- 1 root root    926  7月 14 11:57 pdo.la
-rwxr-xr-x 1 root root 441062  7月 14 11:57 pdo.so

編譯成功,查看一下是否有使用 function_entry

代碼: [選擇]
$ grep "function_entry" *.c
pdo.c:const zend_function_entry pdo_functions[] = {
pdo_dbh.c:const zend_function_entry pdo_dbh_functions[] = {
pdo_dbh.c: const zend_function_entry *funcs;
pdo_stmt.c:const zend_function_entry pdo_dbstmt_functions[] = {
pdo_stmt.c:const zend_function_entry pdo_row_functions[] = {

嗯~ 要改用 zend_function_entry

---
代碼: [選擇]
$ sudo vim php_cconv.c

#include <php.h>
#include <cconv.h>

#include "php_cconv.h"
#ifdef HAVE_CONFIG_H
        #include "config.h"
#endif

//加上這行
#define function_entry zend_function_entry

static function_entry cconv_functions[] = {
    PHP_FE(cconv, NULL)
    {NULL, NULL, NULL}
};

也可以直接改 function_entry  那行
不過如果有多個地方要改的話
還是用 define 比較省事
也不怕會漏掉沒改到

如果有其他程式要改
就另外建立 h 檔吧

存檔後再 make 一次
這樣就能順利編譯了
^_^


28
ubuntu14.04 已釋出3個月,最近開始安裝測試環境來用
不過卻接連碰到幾個雖然小卻是大困擾的問題

一般來說,現在環境不管是哪一種語系界面
中文顯示應該已經很少會出現亂碼的機會
我的桌面環境習慣都是設定為英文界面
一直到 12.04 版,中文顯示都很正常
14.04 常用的套件大致上都也正常
目前就只有 chromium 中文都是亂碼

並不是網頁內容亂碼
而是 bookmark、分頁標題等等這些
如果系統桌面切換為中文就沒亂碼
換回英文界面則還是亂碼
網路爬了幾天也沒找到解法
後來在ubuntu cn論壇找到類似問題

http://forum.ubuntu.org.cn/viewtopic.php?f=8&t=461481

原貼文裡說要裝3種字型檔
經測試後,其實只要裝 ttf-wqy-zenhei

代碼: [選擇]
$ sudo apt-get install ttf-wqy-zenhei
然後重開瀏覧器就可以正常顯示中文書籤跟分頁 ^^

29
雜七雜八 / firefox & google chromium 快速 restart
« 於: 2014-02-21 11:24 »
在此之前,firefox 或是 chromium 常常在用一陣子之後
會發現一直在吃 cpu 到 70% 80% ,甚至更高
之前做法是到 terminal 找出沒有帶網頁的那個
然後 kill 後再開啟, 強迫瀏覽器 restart
這麼做的原因是希望瀏覽器 restart 後能自動
回復原來正開啟的網頁

剛才在 google 爬文時發現,原來這兩個瀏覽器
已經有提供快速 restart 的方法了

firefox:按 shift + f2 開啟『開發者工具列』,然後輸入 restart + [Enter]

chromium:在網址列輸入 chrome:restart + [Enter]

就這樣,瀏覽器會 restart,並回復到先前的狀態(這個好像要另外設定) ^_^

30
以下內容是參考了一些網路上文章
加上自己不斷嘗試與測試的記錄
如有錯誤,請多多指正 ^_^


(Part 1 remaster tc iso)

先了解如何重新打包(remaster) tc 的開機 iso
然後再來編輯符合自己需求的 rootfs

首先,下載 tinycore 5.x ios 檔
我選用 64bit 版的原因是家裡有幾台 8GB 電腦閑置中
如果用 32bit 雖然有打包好的 memcached 直接可以安裝
但是 32bit 系統只能抓到 4GB 啊,所以還是花點時間
用 64bit 系統來製作

載點:http://distro.ibiblio.org/tinycorelinux/5.x/

(host -> 就是我設定打包 tinycore 所使用的系統)
代碼: [選擇]
$ cd ~
$ mkdir tc
$ cd ~/tc
-----
$ sudo git init
-----

先把 iso 掛載起來,並將裡面的資料複製出來

代碼: [選擇]
$ sudo umount mnt
$ sudo mount -o loop,ro iso/org/CorePure64-5.1.iso ./mnt
$ ls mnt/boot
isolinux  modules64.gz  rootfs64.gz  vmlinuz64

$ mkdir x64
$ cp -a mnt/boot x64
$ chmod -R +w x64

修改開機設定,tc 開機畫面預設等待30秒後自動開機,改成 1/3 秒

代碼: [選擇]
$ sudo vim x64/boot/isolinux/isolinux.cfg
label corepure64
        kernel /boot/vmlinuz64
        initrd /boot/rootfs64.gz,/boot/modules64.gz
        append loglevel=3

timeout 300 => timeout 3
$

rootfs64.gz 其實就是開機後所看到的根目錄『/』裡的資料
modules64.gz 則是放一些 driver,如果想讓系統再小一點
也可以將 modules64.gz 解開刪除一些確定用不到的 driver

代碼: [選擇]
$ mkdir rootfs64 repo
$ cd rootfs64
$ zcat ../x64/boot/rootfs64.gz | sudo cpio -i -H newc -d
$ ls
bin  dev  etc  home  init  lib  mnt  opt  proc  root  run  sbin  sys  tmp  usr  var

不要改變 rootfs64 裡面檔案與目錄的權限
在操作 rootfs64 時要注意不要在路徑最前面加『/』
那會變成是在操作 host 系統『/』下的東西 XD

代碼: [選擇]
-----
$ cd ~/tc
$ sudo git add rootfs64
$ sudo git commit -m "最原始的 rootfs64"
-----

不急著加東西進來,先試看看如何打包 rootfs 與 iso 檔

代碼: [選擇]
$ cd rootfs64
$ sudo vim opt/bootlocal.sh

#!/bin/sh
# put other system startup commands here

sleep 1
echo "Hello, World! ^_^"
$

opt/bootlocal.sh 開機時會自動被執行
加了一行 echo,在開機後顯示一行字串
將修改過的 rootfs64 重新打包並做成新的 iso

代碼: [選擇]
$ pwd
~/tc/rootfs64   <---- 注意現在所在的位置

$ ls -l ../x64/boot/rootfs64.gz
-rwxrwxr-x 1 yamaka yamaka 3334090 Jan  4 16:09 ../x64/boot/rootfs64.gz

$ find | sudo cpio -o -H newc | gzip -9 > ../x64/boot/rootfs64.gz
$ ls -l ../x64/boot/rootfs64.gz
-rwxrwxr-x 1 yamaka yamaka 3434839 Feb 10 15:04 ../x64/boot/rootfs64.gz

這是打包 rootfs,再來是 製作成可開機的 iso 檔

代碼: [選擇]
$ mkisofs -l -J -R -V TC-x64 -no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat -o ../iso/TC-x64-v1.0.1.iso ../x64
I: -input-charset not specified, using utf-8 (detected in locale settings)
Size of boot image is 4 sectors -> No emulation
 93.83% done, estimate finish Mon Feb 10 15:08:38 2014
Total translation table size: 2048
Total rockridge attributes bytes: 1391
Total directory bytes: 4096
Path table size(bytes): 38
Max brk space used 23000
5334 extents written (10 MB)

$ ls -l ../iso/TC-x64.iso
-rw-r--r-- 1 yamaka yamaka 10924032 Feb 10 15:08 ../iso/TC-x64.iso

將這個 iso 掛到 vm 然後開機,開機過程不用再等待30秒或按 enter 鍵
開機進入系統後會看到畫面上顯示『Hello, World! ^_^』字串。

代碼: [選擇]
-----
$ scp ../iso/TC-x64-v1.0.1.iso yamaka@uYmk:~/tmp/.
$ cd ~/tc
$ sudo git add rootfs64
$ sudo git commit -m "rootfs64 開機後顯示『Hello, World! ^_^』字串"
-----

PS:
64bit 版的 iso 預設有兩個 gz 檔,如果想將這兩個合併,可以用下面指令

(合併 rootfs64.gz modules64.gz)
代碼: [選擇]
$ zcat *.gz | gzip > boot2/rootfs64.gz
然後要修改 x64/boot/isolinux/isolinux.cfg

    initrd /boot/rootfs64.gz

刪除『,/boot/modules64.gz』


頁: [1] 2 3 ... 13