或曰

-- 2004年2月下旬 --

Last-modified: Mon, 03 Jan 2005 00:15:01 JST
[dynamic,cache:on]
powered by tds-1.6.2

[著者管理] < = > [上旬] [中旬] [下旬] [一覧] [アクセス解析]
[最新版] [2003年12月以前] [2003年2月以前]


お名前 名前記録
一言
最近の一言
09/07 14:38読んだよ
09/07 14:38読んだよ
04/17 20:30ゆんGNU ld 遅い問題。うちの現在進行中のプロジェクトでも同じ問題に悩んでいたのですが、-Mapオプションを外したところ劇的に速度が改善されました。まさかこんな事だったとは。感謝。そして、ボトルネック調査の重要性を痛感した次第です。
03/01 22:40一生>はりあさん ありがとうございます。後でチェックしてみます。
02/28 13:10はりあ失礼します。BYACC / JAVA(http://troi.lincom-asg.com/~rjamison/byacc/) というのがあります。参考までに。

2004/2/20(Fri) [n]

%1

09:00 起床, 10:00 会社着。

%2[Work] お仕事

@ 細かい仕事を

順次、サブプログラマの人にお願いする。 人手があると助かる。

まだ、 どこまで私が枠組みを固めてしまうべきか試行錯誤中。 あまり細かいところまで書いてから渡すと

とお互い不幸になる。 かといって、現状のソース見て書いてくれでは無理なわけで。

ま、その内に適当な距離感がつかめるだろう。

@ カメラ管理クラス

プログラミング設計で存在する数の概念は 0, 1, 2 とあとは沢山。

たとえばカメラ。 シーン中で必要な数が 0 なら、そもそも何も書く必要はない。 1 ならカメラをグローバル変数なりメンバ変数なりで用意して、それを使うだけ。 2 なら真偽値で条件分岐すれば、まぁ良し。 しかし、それ以上なったらハードコーディングせずにマジメに管理しないと破綻する。

これまでカメラはメインを 1 つ、 デバッグ用一つの計 2 つで済ませてきたのだけど、 そろそろ演出用にカメラを多数制御する必要が出てきたので、 カメラ管理クラスをマジメに作ることに。

どういう設計にするか悩んだが、今回はカメラ管理クラスの方に

というようなメッセージだけ投げて、 実際にどう振る舞うかは管理クラス内部で処理する形に。 カメラ管理クラスには「ビュー行列を設定する」メソッドを実装しておき、 レンダリング直前にこれを呼ぶ。

この設計だとカメラ管理クラスがやや複雑な状態を持つことになるため、 カメラ管理クラスを HSM として実装。 まずは MagicDraw でざっとステートチャートを書いて、 それを見ながらコードに落とす。

私が今使っているフレームワークでは、 ステートチャートと C++ コードの距離が近いため、 図を見ながらサクサクとコードを書けて良い感じ。 記法重要。

@ 演出

企画サイドから、 演出の実現可否と、 それをするのに必要なコストについて問い合わせ。

コストに関しては

があり、 さらに演出内容によっては他のデータの作成方法に影響を及ぼす場合もある。

現状で見通せる範囲で実現方法とコストに関して回答しておいて、 加えて 「デザイン素材を発注する前に演出固めて置いた方が良い。後からだと対応できないこともありうる」 と具体例を挙げて説明しておく。 演出が決まった段階で一覧を渡してもらうのは前提として、 それはそれとして随時相談受け付けるので、 何かあったら来てねということに。

実作業に関してはシステムを把握しているプログラマが仕切るしかない。 アイデアを出すところまではともかく、 それを具体化する方法を考え、 そのために必要となる素材をリストアップして、 作れる人間に作業方法を指示するのは、 システム内部を理解している人間以外はできないため。

かくてコードを書く時間が削られて、 ミーティングなどに費やされることになるわけだ。 必要経費だけど。 図を書いたり身振り手振りを交えての議論が必要になるので、 チームのメンバーが物理的に近い位置に集められていることは極めて有効。

@ マシン調達

依頼していたリンク速度の検証結果が返ってきたので、 それを見ながら調達するマシンのスペックを決定。

上長が「そんなにリンク時間かかってるの?」と驚いていたが、 C++ を本格的に使い込むとシンボル数も増えるし、 シンボル名も長くなりがちだから仕方ない気がする。

その内時間が取れたら ld を -pg 付きでコンパイルしてプロファイルを取ってみるか。

@ 帰宅

20:50 離脱。


2004/2/21(Sat) [n]

%1 MovableType

期間限定で、ちょっと 評価中


2004/2/23(Mon) [n]

%1

09:30 起床, 10:30 会社着。

%2[Work] お仕事

@ 事務仕事

消耗品の手配とか、書類書きとか、メール書きとか。

@ エフェクト

こちらもスクリプトベースのものに移行中。

下準備としてサブプログラマに現状のシステム概要を教えて、 いくつか C++ で書いてもらう。 その間に、 エフェクトシステム担当のプログラマが書いたスクリプト制御可能なエフェクトシステムをレビュー。 私の方のゲームシステムに組み込む準備。

@ It's time to decide

そろそろ、決定を先延ばしできない時期に差しかかってる。 仕様のディレクションに関わる人間から技術的な問い合わせが何件かあって、 それに対応。

とか書くと堅苦しそうだけど、 実際にはパーティション挟んで「で、この辺どうなの?」と会話してるだけ。 後々に影響する内容に関しては、 その場でメモを取って ML に流すなりプロジェクトの Web に書くなりして形に残すけど、 そうでなければ立ち話で終わり。

@ コード書き

残っている細かい TODO リストを順に潰す。 システム的に大きな変更を伴う TODO も 2, 3 あるけど、 それは設計が固まってないので後回し。

先週、企画サイドから出てきた新仕様を実装。 新仕様というか、 私が仕様の穴に気づいて、

私「とりあえずこういう仕様で実装しちゃうけど良い?」
相手「良いよ」

で済ませたもの。良くある話。

@ ドキュメント書き

やろうと思ったが時間切れ。 帰ろう。

@ 帰宅

20:10 離脱。

しかしプログラミングと同じぐらい、 情報を右にやったり左にやったりという仕事が多い (今日は多すぎだけど)。

人が増えてくるとプロジェクトに参加している個々人が直接コミュニケーションを取るのが非効率的になってくるから、 情報を階層的に集約してプロジェクト内でのコミュニケーションパスを減らさざるをえない *1。 大きな分野の情報集約点にいると、 自分のことばかりに時間を割いてるわけにはいかないのは世の定め。 その分、 プロジェクト全体の動きがよく見えるけど。


*1:ただし階層は 1 つではなく、分野ごとに異なるヒエラルキーが成立することもある。

%3[Web巡回] Web巡回

@ 並列ビルドの話

soda さん wrote:

Linux の NFS 問題は、linux-2.4.20 以降は直っているようです ( http://nfs.sourceforge.net/ の A8 参照)。あと、当り前すぎて聞き忘れてたんですが一応… 時刻同期は大丈夫だったんですよね? 時刻が狂いすぎていると ntp は同期を諦めちゃうので。

時刻同期は、 マシンを 24 時間つけっぱなし & xntpd 走りっぱなしなので問題ないと思いますが、 もう証拠が失われているので何とも言えません。 次に同じ問題が出たら、時刻もチェックしてみます。

Linux の深いところには関わりたくなかったのだけど、 少しは kernel 動向とかも追うようにしないとダメか。

@ Small - A little scripting language

メモ。

@ ヴァチカン美術館所蔵古代ローマ彫刻展 生きた証-古代ローマ人と肖像

3/2 からか。週末に出かけよう。


2004/2/24(Tue) [n]

%1

08:40 起床, マスク購入に失敗しつつ 10:00 出社。

@ マスク

花粉症対策のマスクを切らしていたので近所の薬局に買いに行ったら、 探してものを置いてなかった。 去年はあったんだけど。

面倒だからネットで注文してしまおう。

%2[Work] お仕事

@ コード読み

別のプロジェクトで同じような処理を実装しているところがあるので、 そのソースコードを入手して調査。

微妙だ、設計思想が違い過ぎる。 細かいところは見なかったことにして、 参考になりそうな部分は参考にさせてもらおう。

@ ドキュメント書き

長らく TODO リストのトップ付近に残っていた、 デザイナ・企画の人向けの「作成したファイルの提出先・形式」をまとめたドキュメントを書く。

@ その心は?

私の書いているコードはインターフェースを多重継承して、 外部にはインターフェースだけ見せる形になっているものが多い。 サブプログラマに「どうしてこういうコードになってるの?」と聞かれたので、 その辺の説明。

伝わった模様。

@ デザイン面での要求

企画・デザインサイドから出てきた要求。 実現方法はある程度予想がつくが、 検証している余裕がなく時間的に無理ということで今回は見送り。

次回スケジュール切り直すときに、 それも入れる方向で。

@ 横のつながりを使う

その件に関して他で実現済みのプロジェクトがあるので、 そちらで担当しているプログラマに話を聞く手筈を整えておく。 上長に人を紹介してもらったら、 入社時にお世話になった方だった。

その場で聞ける簡単な質問をいくつか消化して、 あとは「そのうち詳しい質問をしに来るかもしれないので、よろしく」と挨拶して今日は引き上げ。

@ 上も使う

それはそれとして、せっかく上長を捕まえたので別件で問い合わせ。 言いにくい内容もあるが、口に出しておかないと伝わらないしね。

いろいろなトコロで微妙に連携が悪いが、ま、良いでしょ。

@ 帰宅

20:10 離脱。


2004/2/25(Wed) [n]

%1

09:00 起床, 10:00 会社着。

%2[Work] お仕事

@ メモリまわり

ひっさしぶりにメモリまわりの致命的なバグが二つ。 半日費やす。

ひとつはサブプログラマのコードで delete し忘れている場所があったこと 、もうひとつはプログラムの肥大化に伴い、 アドレス固定で確保していた STL 用アロケータ用メモリ領域とコード領域が重複してしまったこと。

前者は boost::scoped_ptr の使用を強く推奨することと、 読み込んだファイルを解放する際に、 モデル・テクスチャ管理クラスで整合性チェックを行うようにして再発防止。

後者は事前に二つ対策を講じてあったのだけど、 どちらもすり抜けてしまったので、 原因究明に手間取った。

対策と結果

後者について補足。 たとえば FreeBSD 4.x の標準リンカスクリプトは /usr/libdata/ldscripts/elf_i386.x にあるが、 これを見るとコード領域 (.text) とデータ領域の境目のアドレスに etext シンボルを定義してある。 C, C++ から境目のアドレスを取得するには、 変数 etext の「値」ではなく「アドレス」を参照する必要がある。

#include <stdio.h>

extern int etext;

int
main()
{
    printf("%p\n", &etext);
}

チェックコードで & をつけ忘れていたため、 正常に働いていなかったという次第。

@

サブプログラマの人用にスクリプトシステムの環境を整えたり、 スクリプトからゲームオブジェクトの状態遷移を要求するシーケンスを設計したりで、 自分のコードを書いてる時間が取れなかった一日。

どうにか 19:00 ぐらいからコードを書き始めたが、 いい加減に疲れたので帰ることに。 メモリまわりのバグは精神的に疲れる。

@ 帰宅

21:00. 遅すぎ。


*1:GNU リンカ LD の使い方: 3.6 SECTIONS コマンド 参照。


2004/2/26(Thu) [n]

%1

08:40 起床, 10:00 会社着。

%2[Work] お仕事

@ cc1plus

私の作業中に 以前に 入れておいた wrapper が動く場面に遭遇。 よしよし、ちゃんと動いてるね。

出力メッセージがイマイチだったので修正しておく。

@ ゲームオブジェクト

処理の内容が入り組んできたので、 シグナル種別と処理順序を見直し。 これまでシグナル種別 4 通つで済ませていたのを、 意味に応じて細分し名前をつけ直す。

処理内容には、 そのインターでは登録要求だけしておいて判定は後で一括して行う必要があるものと、 その場ですぐに処理する必要があるものと二通りある。 これを間違えるとゲームオブジェクトの処理順序によって有利・不利が出たり、 極めて希なタイミングで妙な状態に陥ったりするので、 処理順序は慎重に決める必要がある。

スクリプトによる状態遷移要求は汎用ではなく、 非常に制限された遷移要求だけを行える関数だけを提供。 また、状態遷移要求があっても即座に処理せず、 必ずシステム側でチェックを入れてから処理するようにしてある。

状態遷移はデリケートなところで、 プログラムの内部構造を完全に理解してないスクリプタに、 全て開放するわけにはいかないため。 まだエラーチェックが甘い部分があるので、 もう少し制約をきつくしよう。

@ スクリプトドリブン

ゲームオブジェクトの処理シーケンスが固まったので、 スクリプト側に提供する機能を追加。 タイミングが絡むものは、 全部スクリプトで書かせる形に持って行く予定。 設計は固まったから、 あとは時間さえあれば実装はどうにかなるだろう。

(仕様が増えるまでは)

@ スクリプトシステム

型関係で要望が出てきたので、 担当のメインプログラマと話。 目指す方向は決まったので、 近いうちに実装する方向で。

それはそれとして、 Java か C++ あたりでコードを書ける LR(1) LALR(1) パーサを生成するパーサージェネレータがないかという話に。 現在は GNU bison を使っているのだけど、 これは C でコードを書く必要があるため、 いろいろ面倒。

LL(1) で良ければ自分でパーサを書くのは難しくないし、 LL(k) なら antlr があるのだけど。

とりあえず google に聞いてみた結果。リンク先はざっと眺めただけで、マジメに読んでません。

SLR(1) や LR(1) LALR(1) だけでなく GLR を解析できるパーサージェネレータもあるのか。 重そうだけど。

@ メモリまわり

昨日の メモリまわりの件。AoiMoe の人のアドバイスに従って、 未定義 (宣言のみ) の構造体を使う形に書き直し。

C++ だと変数シンボルには型情報が埋め込まれないので、 こういう細工が可能なのか。 うまい方法ですね。

@ 歓迎会

開催。


2004/2/27(Fri) [n]

%1

09:00 起床, 10:00 会社着。

%2[Work] お仕事

@ コンパイラコンパイラ

昨日リストアップしたものについて、使えそうか順次調べる。 良さそうなものが幾つか。

緊急ではないので、 リンク集だけ社内ページに作ってしばらく放置。

@ バグ潰し

メモリリークしている部分を潰す。 グローバルな管理オブジェクトで、

// 登録
g_obj.load(id);
...
// 削除
g_obj.release(id);

みたいに対にして使うものが幾つかあるのだけど、 他の人が書いたコードで load() したまま release() してない箇所が幾つか。

手作業で load(), release() すると忘れるだろうということで、 変数スコープに従って処理するヘルパクラスを用意してある。 概略、次のような代物。

class OBJ_HANDLER
{
public:
	OBJ_HANDLER() : m_id(0), m_flag(0) {}
	OBJ_HANDLER(int id, int flag) : m_id(id), m_flag(flag) { g_obj.load(m_id, m_flag); }
	~OBJ_HANDLER() { g_obj.release(m_id); }
	// あとコピーコンストラクタと代入演算子も適当に定義

private:
	int m_id;
	int m_flag;
};

直接グローバルなオブジェクトを触るのは禁止。 全面的にこちらに移行してもらう。

@ id -> OBJ_HANDLER()

複数の id を一括して登録・削除したい場合は、 コンテナに OBJ_HANDLER() をまとめて登録すればいい。 自前でループ回して登録しても良いけど、 std::transform と boost::lambda を使うとこんな感じで書ける。

#include <algorithm>
#include <iterator>
#include <vector>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>
#include <boost/lambda/construct.hpp>

#define NELEM(x)        (sizeof(x) / sizeof(x[0]))

int
main()
{
    int const tbl[] = { 1, 3, 8, 9, };
    int const FLAG = 1;

    std::vector<OBJ_HANDLER> handlers;

    using namespace boost::lambda;
    std::transform(
        &tbl[0], &tbl[NELEM(tbl)],
        std::back_inserter(handlers),
        bind(constructor<OBJ_HANDLER>(), _1, FLAG)
        );
}

lambda 深いな。ドキュメントを読むたびに新たな発見がある。

@

データの作成依頼を出したり、 問い合わせに対応したり、 自分のコード書いたりといろいろ。

わりと順調に TODO リスト消化中。

@ 帰宅

20:50 離脱。

%3[Web巡回] Web巡回

@ JavaCC

すぎむらさん wrote:

LR なのかどうかは知りませんが、JavaCC などは評価されていますか。

情報ありがとうございます。 JavaCC は情報も豊富にあるため検討したのですが、 扱える言語が LL(k) だったために除外しました。

あと正確には yacc は LR(1) ではなく、そのサブセットである LALR(1) を扱います。 昨日の日記だと LR とだけ書いてあったので、微妙に修正しときました。

文法は

を並べて定義できますが、 左辺の非終端記号を展開した結果として右辺の先頭に同じ非終端記号に出てくる場合、 その文法は「左再帰を含む」と言います。 LL(k) には「左再帰を含んではいけない」という制約があり、 これが面倒の種。

例: LL(k) に含まれない文法

 E -> T | E '+' T
 T -> F | T '*' F
 F -> '(' E ')' | id

ただし '+', '*', '(', ')', id が終端記号。 これは加算・乗算と括弧だけからなる四則演算のサブセットですが、 E -> E '+' T などが左再帰になっているため、 LL(k) ではありません。

この程度なら簡単な書き換えで LL(1) になりますが、 書き換えが面倒なのと、 書き換え処理によって余計な非終端記号が増えて文法が煩雑になりがちなので、 私は LALR(1) を扱えるコンパイラジェネレータの方が好きです。

 E  -> T E1
 E1 -> '+' T E1 | ε
 T  -> F T1
 T1 -> '*' F | ε
 F  -> '(' E ')' | id

ただしεは空記号。

LR 系のコンパイラジェネレータを使うと、 代わりにエラー回復が難しかったり、 例外的な処理を入れるのが難しくなりますが、 そこまで本格的な言語を書かないので。


2004/2/28(Sat) [n]

%1 マジスパ

ビーフ, 虚空 50, スープ大盛り, ライス大盛り, 木耳, ココナッツアイス。 次は 100 に上げるか。


以上、8日分です。 (直前の日記

このページはTomsoft Diary System 1.6.2を用いて生成されています。
Copyright (C) 2004
Issei Suzuki <issei@issei.org>