2014年10月18日土曜日

Javaの軽量スレッドプール的なもの

普通ThreadPoolはRunnable とThreadの関係が切り離されている。そこがオーバーヘッドになるんじゃないかと思って、ThreadとRunnableが1対1に対応していて、複数のスレッドが、それぞれのRunnableをバリア同期を取りながら繰り返し実行する物を書いてみた。
使い方はこんな感じ。tick() とやると、スレッドが一気に動いて、全部終了したところで戻ってくる。
ThreadBundle tb = new ThreadBundle();
 for (int i = 0; i < numThreads; i++) 
  tb.addRunnable(new Runnable() {
     public void run() {
         System.out.print("-");
         System.out.flush();
        try {Thread.sleep(1000);} catch (InterruptedException e) {     }
     }
  });
tb.start();
for (int i = 0; i < 100; i++) 
     tb.tick();
tb.shutdown();
実装は、ReadWriteLockを2つ使って実現している。ワーカスレッドはreadlock を取得しようとしていて、ブロックしている。マスタスレッドがtick でwriteLockをリリースすると、一斉に走る。
一方、ワーカスレッドは裏のreadlockを取得したまま実行しており、これを実行終了後にリリースする。全てのワーカスレッドが裏のreadlockをリリースすると、マスタスレッドがwriteLockを取得できる。これをもって、バリア同期が実現される。
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ThreadBundle {
 List<Runnable> runnables = new ArrayList<Runnable>();
 boolean started =false;
 Thread [] threads;
 ReadWriteLock [] rwlocks = new ReadWriteLock [] {new ReentrantReadWriteLock(), new ReentrantReadWriteLock()};
 CountDownLatch latch;

 class WrapperRunnable implements Runnable {
  Runnable inner;
  int ic = 0;

  WrapperRunnable(Runnable inner) {
   this.inner = inner;
  }

  @Override
  public void run() {
   rwlocks[(ic + 1 )% 2 ].readLock().lock();
   latch.countDown();
   while (true) {
    //System.out.println("try readLock " + (ic %2));
    rwlocks[ic % 2].readLock().lock();
    //System.out.print("-");
    //System.out.flush();
    inner.run();
    rwlocks[(ic+1) % 2].readLock().unlock();
    ic++;
   }
  }
 }

 public void ThreadBundle() {
 }

 public void addRunnable(Runnable r) {
  if (started)
   throw new RuntimeException("already started");
  runnables.add(r);
 }

 public void start() throws InterruptedException {
  started = true;
  threads = new Thread[runnables.size()];
  latch = new CountDownLatch(runnables.size());   
  for (int i = 0; i < runnables.size(); i++)
   threads[i] = new Thread(new WrapperRunnable (runnables.get(i))); 

  rwlocks[0].writeLock().lock();
  for (int i = 0; i < runnables.size(); i++)
   threads[i].start();
  latch.await();
 }

 int counter = 0;

 public void tick() {
  rwlocks[counter % 2].writeLock().unlock();
  rwlocks[(counter + 1) % 2].writeLock().lock();   
  counter++;
 }

 public void shutdown() {
   // 手抜き  
 }
}
結構凝った仕掛けなのに、あんまり速くない?残念。

2014年10月12日日曜日

CUDA

CUDAがちゃんとインストールできてるのかチェックするために、 ググって見つけた
こちらをコピペしてみたところ、コンパイルできない。。。
調べてみると、CUDAのバージョンが違うのが原因。というか厳密にはサンプルについてくる、Wrapperの仕様が変わったせいらしい。まあ、そういうこともあるだろう。
  • cutilSafeCall -> checkCudaErrors
  • CUTIL_SAFE_CALL -> checkCudaErrors
  • タイマー周りはAPIそのものが変わってる?
    cudaEvent_t を使う。
  • include するファイルも変更
#include <stdio.h>
#include <stdlib.h>
#include <helper_cuda.h>
#include <helper_functions.h>

#define MATRIX_SIZE 1024/*行列1辺の数*/
#define BLOCK_SIZE 16

__global__ void
matrixMul(int* inMatrixA, int* inMatrixB, int* inMatrixC);

int main(int argc, char** argv){
unsigned int matrixSize = sizeof(unsigned int) * MATRIX_SIZE * MATRIX_SIZE;

  int* hMatrixA;
  int* hMatrixB;
  int* hMatrixC;
  hMatrixA = (int*)malloc(matrixSize);
  hMatrixB = (int*)malloc(matrixSize);

/*初期値設定*/
  unsigned int col_idx, row_idx;
  for (col_idx = 0; col_idx < MATRIX_SIZE; col_idx++){
      for (row_idx = 0; row_idx < MATRIX_SIZE; row_idx++){
          hMatrixA[col_idx * MATRIX_SIZE + row_idx] = rand() % (1024*1024);
          hMatrixB[col_idx * MATRIX_SIZE + row_idx] = rand() % (1024*1024);
      }
  }

/*デバイス側の変数設定*/
  int* dMatrixA;
  int* dMatrixB;
  int* dMatrixC;

/*デバイスメモリ領域の確保*/
  checkCudaErrors(cudaMalloc((void**)&dMatrixA, matrixSize));
  checkCudaErrors(cudaMemcpy(dMatrixA, hMatrixA, matrixSize, cudaMemcpyHostToDevice));
  checkCudaErrors(cudaMalloc((void**)&dMatrixB, matrixSize));
  checkCudaErrors(cudaMemcpy(dMatrixB, hMatrixB, matrixSize, cudaMemcpyHostToDevice));
  checkCudaErrors(cudaMalloc((void**)&dMatrixC, matrixSize));

/*ブロックサイズとグリッドサイズの設定*/
  dim3 block(BLOCK_SIZE, BLOCK_SIZE);
  dim3 grid(MATRIX_SIZE/BLOCK_SIZE, MATRIX_SIZE/BLOCK_SIZE);

/*タイマーを作成して計測開始*/
  cudaevent_t start;
  cudaEvent_t stop;
  checkCudaErrors(cudaEventCreate(&start));
  checkCudaErrors(cudaEventCreate(&stop));

  checkCudaErrors(cudaEventRecord(start, NULL)); // スタート

/*カーネルの起動*/
  matrixMul<<<grid, block>>>(dMatrixA, dMatrixB, dMatrixC);
  cudaThreadSynchronize();

/*結果の領域確保とデバイス側からのメモリ転送*/
  hMatrixC = (int*)malloc(matrixSize);
  checkCudaErrors(cudaMemcpy(hMatrixC, dMatrixC, matrixSize, cudaMemcpyDeviceToHost));

/*タイマーを停止しかかった時間を表示*/

  checkCudaErrors(cudaEventRecord(stop, NULL));
  checkCudaErrors(cudaEventSynchronize(stop));

  float msecTotal = 0.0f;
  checkCudaErrors(cudaEventElapsedTime(&msecTotal, start, stop));

  printf("Processing time: %f (msec)\n", msecTotal);

/*ホスト・デバイスメモリの開放*/
  free(hMatrixA);
  free(hMatrixB);
  free(hMatrixC);
  checkCudaErrors(cudaFree(dMatrixA));
  checkCudaErrors(cudaFree(dMatrixB));
  checkCudaErrors(cudaFree(dMatrixC));

/*終了処理*/
  cudaThreadExit();
  exit(1);
}

__global__ void
matrixMul(int* inMatrixA, int* inMatrixB, int* inMatrixC){
  unsigned int col_idx = blockIdx.x * blockDim.x + threadIdx.x;
  unsigned int row_idx = blockIdx.y * blockDim.y + threadIdx.y;
  unsigned int scan_idx;
  unsigned int target = 0;

/*行列の演算を行う*/
 for (scan_idx = 0; scan_idx < MATRIX_SIZE; scan_idx++) {
   target +=inMatrixA[col_idx * MATRIX_SIZE + scan_idx] * inMatrixB[scan_idx * MATRIX_SIZE + row_idx];
   __syncthreads();
 }
 inMatrixC[col_idx * MATRIX_SIZE + row_idx] = target;
}

2014年9月2日火曜日

macbook pro retina 15 mid 2012 でCUDA

  • https://developer.nvidia.com/cuda-downloads から、CUDA本体?をダウンロードサイズも842MBとでかいし、結構時間がかかる。
  • ドライバだけ先に別途インストールしてしまったが、上記ファイルにドライバも入ってるので無駄だった模様。
  • SystemPreference にCUDA Preferenceというパネルが出る。そこからドライバのアップデートが可能。
  • /Developer/NVIDIA/CUDA-6.5/ というディレクトリができてる。
  • 再起動は不要とのこと。本当だろうか。
  • bin/cuda-install-samples-6.5.sh* XXX とやるとサンプルをXXXにコピーしてくれる。そこでmake と打つと大量のサンプルをコンパイルしてくれる。
  • びっくりするぐらいコンパイルが遅いぞ?と思ったら、たんに大量だっただけ?
  • XXX/bin/x86_64/darwin/release 以下に大量のサンプルができる。
> ./deviceQuery                                    [~/projects/cuda/NVIDIA_CUDA-6.5_Samples/bin/x86_64/darwin/release]
./deviceQuery Starting...

 CUDA Device Query (Runtime API) version (CUDART static linking)

Detected 1 CUDA Capable device(s)

Device 0: "GeForce GT 650M"
  CUDA Driver Version / Runtime Version          6.5 / 6.5
  CUDA Capability Major/Minor version number:    3.0
  Total amount of global memory:                 1024 MBytes (1073414144 bytes)
  ( 2) Multiprocessors, (192) CUDA Cores/MP:     384 CUDA Cores
  GPU Clock rate:                                900 MHz (0.90 GHz)
  Memory Clock rate:                             2508 Mhz
  Memory Bus Width:                              128-bit
  L2 Cache Size:                                 262144 bytes
  Maximum Texture Dimension Size (x,y,z)         1D=(65536), 2D=(65536, 65536), 3D=(4096, 4096, 4096)
  Maximum Layered 1D Texture Size, (num) layers  1D=(16384), 2048 layers
  Maximum Layered 2D Texture Size, (num) layers  2D=(16384, 16384), 2048 layers
  Total amount of constant memory:               65536 bytes
  Total amount of shared memory per block:       49152 bytes
  Total number of registers available per block: 65536
  Warp size:                                     32
  Maximum number of threads per multiprocessor:  2048
  Maximum number of threads per block:           1024
  Max dimension size of a thread block (x,y,z): (1024, 1024, 64)
  Max dimension size of a grid size    (x,y,z): (2147483647, 65535, 65535)
  Maximum memory pitch:                          2147483647 bytes
  Texture alignment:                             512 bytes
  Concurrent copy and kernel execution:          Yes with 1 copy engine(s)
  Run time limit on kernels:                     Yes
  Integrated GPU sharing Host Memory:            No
  Support host page-locked memory mapping:       Yes
  Alignment requirement for Surfaces:            Yes
  Device has ECC support:                        Disabled
  Device supports Unified Addressing (UVA):      Yes
  Device PCI Bus ID / PCI location ID:           1 / 0
  Compute Mode:
     < Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) >

deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 6.5, CUDA Runtime Version = 6.5, NumDevs = 1, Device0 = GeForce GT 650M
Result = PASS

2014年7月26日土曜日

ubuntu のキーバインド

いつもinstallするたびにアプリでのデフォルトキーバインドをEmacsに変更する作業をやるのだけど、そのたびに方法が変わっててホント嫌になる。とりあえず14.04では
gnome-tweak-tool
をインストールして、それらしい項目を変更することでうまく行った。
もっといい方法があるのかどうかは知らない。

2014年7月11日金曜日

Macbook pro でUSBがおかしくなったとき

なぜだかわからないが、私のMacbook Pro Retina 15は、USBが反応しなくなることがある。多分どこかハードウェア的におかしくなってるんだと思うのだが、リブートすると復活する。しかしいちいちリブートすると、デスクトップの状態が失われて面倒。
多分電源をオンオフすればいいのではないかと思い、ハイバネーションをためしてみた。とはいえ、Macでは普通はスリープするのでハイバネーションさせることができない。
そこで、強制的にハイバネーションするようにディープスリープモードにする。
sudo pmset -a hibernatemode 1
これで普通にスリープさせると、ディスクに状態を書き出して完全に電源が落ちる。USBも復活。
復活したらスリープモードをもとに戻しておく。
sudo pmset -a hibernatemode 3

2014年7月2日水曜日

Google sites で markdown

問題

Google sites はWysiwigエディタが付いてるのだけどとてもうざい。

解決策

MarkDown HereというChromeExtensionを入れるとMarkDownで編集できる。
とても楽。もともとGmail用のものらしいのだけどSitesでも動く。
実はこのExtension, Bloggerでも機能する。ということでこれもMarkDownで書いてみた。いつもはHTML直打ちなのでずっと楽だ。。

2014年6月24日火曜日

xubuntu のxfce4での emacs キーバインド設定

Xfceを用いるubuntu ディストロ xubuntuでのEmacsキーバインド化。 Settings Editor でxsetting -> KeyThemeName をEmacsにすればよい。

2014年6月14日土曜日

docbook -> pdf

すごく試行錯誤したのでまちがってるかもしれないが。 Mac,brew で。
> brew intall docbook docbook-xsl fop
で、
fop -c fop.conf -xsl docbook.fo.xsl -xml INFILE -pdf OUTFILE
fop.confは、
<?Xml version="1.0" encoding="UTF-8" ?>

<fop version="1.0">
 <renderers>
  <renderer mime="application/pdf">
   <filterlist>
    <value>flate</value>
   </filterlist>
   <fonts>
    <auto-detect />
   </fonts>
  </renderer>
 </renderers>
</fop>
docbook.fo.xml は
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version='1.0' xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:import href="file:////usr/local/Cellar/docbook-xsl/1.78.1/docbook-xsl/fo/docbook.xsl"/>
  <xsl:param name="l10n.gentext.default.language">ja</xsl:param>
  <xsl:param name="ulink.show" select="0"/>
  <xsl:param name="paper.type">A4</xsl:param>
  <xsl:param name="hyphenate">false</xsl:param>

  <xsl:param name="callout.unicode" select="1"></xsl:param>
  <xsl:param name="callout.graphics" select="0"></xsl:param>

  <xsl:param name="title.font.family">Meiryo</xsl:param>
  <xsl:param name="body.font.family">Meiryo</xsl:param>
  <xsl:param name="monospace.font.family">MS Gothic</xsl:param>
</xsl:stylesheet>
Macなのに、Meiryoにしているのは他のフォントではうまく行かなかったから。 Osaka, Hiraginoあたりは試したけどだめだった。IPAフォントならうまくいくらしい。

fop がメモリ不足で落ちたりするので、そのときは/usr/local/Cellar/fop/1.1/libexec/fop を編集して

java_exec_args="-Xmx1G -Djava.awt.headless=true"
とかやるとOK。