2015年6月25日木曜日

PostgreSQLのロック確認方法

どうも、俺です。

PostgreSQLで発生しているロックの確認の方法です。

PostgreSQL:ロックの確認と解除方法

上記にありますが、

SELECT l.pid, db.datname, c.relname, l.locktype, l.mode
FROM pg_locks l
        LEFT JOIN pg_class c ON l.relation=c.relfilenode
        LEFT JOIN pg_database db ON l.database = db.oid
  WHERE datname='{DATABASE_NAME}'
ORDER BY l.pid;

です。

9.6. ロックとテーブル
にあるように、クエリ実行中は数種類のロックがかかっています。

実際に測ってみると、
SELECT文でも AccessShareLockがかかりますが、
これはAccessExclusiveLockモードとのみ競合するとのことなので、
ALTER TALBE, DROP TABLE, VACUUM FULL, LOCK TABLE
以外のクエリに対しては何ら問題ありません。


以上でぇぇぇぇす。

2015年6月24日水曜日

PostgreSQLのキャッシュヒット率計算

どうも、俺です。

PostgreSQLのキャッシュヒット率の計算をググって出てきたのでメモ。

以下のサイトに書いてありました。
稼動統計情報を活用しよう(2)

・テーブルへのキャッシュヒット率の計算
SELECT relname,
   round(heap_blks_hit*100/(heap_blks_hit+heap_blks_read), 2)
   AS cache_hit_ratio FROM pg_statio_user_tables
     WHERE heap_blks_read > 0 ORDER BY cache_hit_ratio;


・インデックスのキャッシュヒット率の計算
SELECT relname, indexrelname,
   round(idx_blks_hit*100/(idx_blks_hit+idx_blks_read), 2)
   AS cache_hit_ratio FROM pg_statio_user_indexes
     WHERE idx_blks_read > 0 ORDER BY cache_hit_ratio;


以上でぇぇぇぇす。


※2015.6.25 追記

postgresql_トラブルシュート
を参考にテーブルキャッシュヒット率とインデックスヒット率を同時に計算できるんじゃないかと考えました。
利用するテーブルはpg_statio_user_tablesです。
SELECT *,
(heap_blks_hit*100) / (heap_blks_read+heap_blks_hit) AS disk_ratio,
(idx_blks_hit*100) / (idx_blks_read+idx_blks_hit) AS idx_ratio
FROM pg_statio_user_tables
WHERE heap_blks_hit >= 1
and schemaname = 'public' ORDER BY idx_ratio;

統計情報を持つテーブルについてはこちら(統計情報コレクタ)を参考に。

ただ、なぜかこのクエリだといくつかのインデックスヒット率は、上述したクエリで算出したものと異なる場合がある。。
なので、修正しないといけない...。


※2015.6.26 追記
キャッシュヒット率の合計平均を出すクエリを作りました。

・テーブルへのキャッシュヒット率平均
SELECT avg (cache_hit_ratio)
FROM
(SELECT relname,
   round(heap_blks_hit*100/(heap_blks_hit+heap_blks_read), 2) AS cache_hit_ratio 
FROM pg_statio_user_tables
     WHERE heap_blks_read > 0) AS foo;

・インデックスヒット率の平均
SELECT avg(cache_hit_ratio)
FROM
(SELECT relname, indexrelname,
   round(idx_blks_hit*100/(idx_blks_hit+idx_blks_read), 2) AS cache_hit_ratio 
FROM pg_statio_user_indexes
WHERE idx_blks_read > 0) AS foo;

統計情報をリセットする場合は
SELECT pg_stat_reset();
を叩けばリセットされます。

設定を変更して統計を取り直したい場合などに使います。

2015年3月6日金曜日

cocos2d-xのメモリ対策について

どうも、俺@仕事中です。

昨年、cocos2d-x CCSprite(テクスチャ)の軽量化という記事を書きましたが、
今回も同じようにメモリ対策についてメモ。

■環境
・cocos2d-x 2.2.6
・Xcode 6.1.1

先に結論から言いますと、
CCSpriteFrameCacheやCCTextureCacheの使いすぎに注意、
または、メモリ不足に陥る前に正しくキャッシュデータを解放しましょう。
ということです。

CCSpriteFrameCacheCCTextureCacheは、
スプライトシートなどの画像データをメモリ上にキャッシュしてくれるため、
CCSpriteオブジェクトの生成時に高速&低負荷であることがメリットな反面、
メモリを消費します。(※1)

特にCCSpriteFrameCacheは大きなサイズは画像ファイル(スプライトシート)を
キャッシュすることがあるのでそのメモリ消費には要注意です。


例えば、
タイトル画面(TitleScene) → 遷移 → ゲーム画面(GameScene)
のような場合。

タイトル画面で表示するためのスプライトシートを読み込み、
またゲーム画面でもゲーム画面用のスプライトシートを読み込み、
といった処理を行うと、
両方の画面で読み込まれたスプライトシートはキャッシュされたままになります。




メモリが不足してくると、iOSでは
    AppController#applicationDidReceiveMemoryWarning:(UIApplication *)application; 
がコールされ、
cocos2d-xのバージョンによっては、
    CCDirector#purgeCachedData(void)
が呼ばれて、開発者が意図せず勝手にキャッシュデータが消去されます。

この状態だと、次にCCSpritFrameCacheからキャッシュデータを読み込もうとすると
エラーとなりアプリがクラッシュしてしまいます。


対応として、
1)CCDirector#purgeCachedData(void)を呼ばない。
2)不要になったタイミングでCCSpriteFrameCacheのキャッシュデータをクリアする。
が考えられます。

1)の方法は簡単&すぐに対応できますが、メモリ逼迫の原因は解消されません。
2)は、画面遷移の前などで
    CCSpriteFrameCache::sharedSpriteFrameCache()->removeSpriteFramesFromFile(const char *plist);
を呼べばOKです。

画面遷移の前というのは、
CCDirector#replaceScene(CCScene *pScene)
を呼ぶより前のタイミングです。
その該当するSceneのonExit()やデストラクタ内で、
    CCSpriteFrameCache::sharedSpriteFrameCache()->removeSpriteFramesFromFile(const char *plist);
を呼ぶと、
すでに遷移先のSceneオブジェクトが生成されてしまっているので、
タイミングとしてはちょっと遅いです。

※1) CCSpriteクラスのcreate(const char *fileName)メソッドや
initWithFile(const char *fileName)メソッドは、
内部でCCTextureCacheクラスのaddImage(const char *fileName)が呼ばれているため、
キャッシュされ、二回目以降の呼び出しは高速になる。


以上でぇぇぇぇぇす。

2015年1月26日月曜日

cocos2d-x Androidで"could not create track"エラー

どうも、俺@もう帰るです。

今日は、cocos2d-xでAndroid対応している時にハマった
AudioFlinger could not create track, status: -12

のエラーについてです。

・Xcode v6.1
・cocos2d-x v2.2.6
・eclipse Juno Service Release 2

現象ですが、
ゲーム開始時に、エンジンの効果音(.oggファイル)を
    int soundID = CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("engineSound", true);
上述のようにループ再生させておき、
ポーズのタイミングなどでは効果音を停止させます。
    CocosDenshion::SimpleAudioEngine::sharedEngine()->stopEffect(soundID);

で、またゲーム再開させたときに、
    int soundID = CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect("engineSound", true);
最初は出ていたエンジン効果音が鳴らなくなる、
という症状になってしまいました。

その際、eclipseに出ていたエラーログは、
01-26 18:00:00.000: ERROR/AudioTrack AudioFlinger found not create track, status: -12
01-26 18:00:00.000: ERROR/AudioTrack Error creating AudioTrack
でした。

Webで調べたところ、
status: -12
というのは、
効果音をロードしてTrackを生成する時に必要となる
リソース(メモリ)不足が主な原因のようです。

しかし僕の場合は
それほどメモリを消費するような大きなサイズのサウンドファイルもない。

他にも調べてみて、以下の方法で解決できました。
anddev.org - SoundPool crashing with "could not create track"

該当のサウンドファイル(.ogg)のビットレートを
ステレオ320kbpsからモノラルの192kbsに下げました。

何kbpsにするのが適正なのかは定かではありませんが、
上記のようにしても音に大きな劣化などは感じられませんでした。
もし同じ症状で悩んでいる方がおられましたら、試してみてください。

以上でぇぇぇぇぇぇす。


2015年1月8日木曜日

64bit(arm64)対応するとJSONKitがエラー[iOSアプリ]

どうも、俺です。

Xcode開発でアーキテクチャにarm64を追加すると
組み込んだ3rdパーティ製ツールのJSONKitからエラーが出てビルドできません。



githubを見ると、JSONKitはかなり長い間更新が止まっており
arm64アーキテクチャに対応していないようです。

この場合は、
該当のエラーが出ている箇所にマウスポインタを併せてクリックし、
エラーを修正してしまえば対応できます。


エラー箇所は2箇所あります。


または、
元のJSONKitをフォークして64bit対応したソースが公開されているので、
そちらでも対応出来ると思います。(※未確認)


以上でぇぇぇぇぇぇす。