5

私は、システムのプロファイリングと分析を行った後、システムのロギング コンポーネントが総実行時間の約 17% を占める多くのボトルネックの 1 つであるという結論に達しました。 .

このうち、ロガーが消費する時間の約 5% は、次の形式で日付/時刻スタンプを ascii で生成することに関連しています。(約 700K x (localtime および gettimeofday) 呼び出し/秒)

私は、タイムスタンプを効率的に生成するために仲間の SOer がどのようなテクニックを持っているのか疑問に思っていました。

クロスプラットフォーム ソリューションは歓迎されます。

注 1: Boost.datetime を調べました - 素晴らしいですが、私たちのニーズには少し遅すぎます。std::chrono は完璧なソリューションですが、残念ながら c++11 より前のコンパイラをサポートする必要があります。

注 2: 日付部分 (yyyymmdd) を 24 時間ごとに 1 つだけ計算する単純な最適化を実装したため、1 行に 1 回の gettimeofday 呼び出ししかありませんが、あまり役に立ちませんでした。

4

3 に答える 3

3

C ++ 11を使用するオプションがある場合は、std::chronoを確認する必要があります。

それができない場合、最適化は必要な解像度に依存します。ロギングにタイムスタンプが絶対に必要かどうか、またはシーケンス情報を含む時折のタイムスタンプが役立つかどうかを尋ねます。

例:

<timestamp1> <seq_num_0> ...
<timestamp1> <seq_num_1> ...
....
<timestamp1> <seq_num_n-1> ...
<timestamp2> <seq_num_0> ...

私の見方では、2つの問題があります。

  1. タイムスタンプを他のシステムと同期する
  2. 単一のシステムで正確なタイムスタンプを取得する

タイマーベースのシステムを使用して、タイムスタンプをミリ秒ごとに2回更新し、更新の合間に再利用します。次に、コードが実行されているシステムのクロックが原子時計に同期していることを確認します。タイムスタンプを2回生成して、基盤となるOSのタイマーメカニズムの不安定さを補正しようとします。

私はあなたがそれよりもはるかに良くなることができるとは思わない。

編集:実際には、できます。タイムスタンプ文字列は、変更されたときにのみフォーマットするようにしてください。エントリが入ってくる順序でログに記録されることを保証できる場合は、シーケンス番号も必要ありません。これら2つの仮定を前提とすると、ログの問題は、2つの文字列を連結して書き出す速度にまで減少します。

更新2:BOOSTが適切でなく、C ++ 11を使用できない場合、要約すると次のようになります。

  1. タイマーを使用して、タイムスタンプをミリ秒ごとに2回設定およびフォーマットします。これは、OSレベルのAPIを介して行うことができます。
  2. イベントが発生した順序でログに記録されていることを確認してください。

I / Oがボトルネックではないと仮定すると、問題は高速な文字列連結の1つに他なりません。

于 2012-08-06T04:41:59.913 に答える
0

実際に必要になるまで、すべてのフォーマットを遅らせます。

struct log_entry {
    struct timeval timestamp;
    unsigned int code;
    union {
        struct param1 p1;
        struct param2 p2;
    };
};

paramN構造体には、イベントに適したデータがその時点での形式で含まれていますが、コピーとして (ログ データをスタンドアロンで分析できるように) 含まれています。

要件に応じて、このデータをリング バッファーに保持し、古いデータを常に上書きするか、特定のパーセンテージに達したときにディスクにダンプすることができます。

于 2012-08-06T06:44:18.183 に答える
-1

編集:現在、複数の反対票を投じています。問題に適切に対処できるように、コメントを残してください。ありがとう!

ロガーが他のスレッドによって 1 秒間に N 回更新される (目的の解像度に応じて) 日付タイムスタンプ文字列を読み取るように、コードを再編成することができます。1 秒間に 4 回:

struct current_time_stamp {
    char timestr_[4][16];
    unsigned index_;
    unsigned subsecond_;
    const char *get () const { return timestr_[index_%4]; }
    void update () {
        // ... update string in timestr_[(index_+1)%4] ...
        // ... if (index_ + 1)%4 is zero, recompute subsecond_
        ATOMIC_INCREMENT(index_);
        // ... also need a memory barrier for timestr_ update
    }
};

各ログの 1 秒未満の解像度は、高性能カウンターから読み取られます。DeadMG はQueryPerformanceTimerWindows で提案し、Linux (および POSIX) ではclock_gettime. ただし、これらの実装のオーバーヘッドが依然として高い場合は、インライン アセンブリを使用して、プロセッサのタイム スタンプ カウンターを直接クエリできます ( rdtscx86 については、「 」を参照)。1 秒未満の値は、適切なオフセットを取得するために、構造体に記録された値からデルタ化されます。

タイムスタンプをバイナリ形式でログに記録することができれば、形式の問題は回避できます。

于 2012-08-06T06:20:21.500 に答える