11

アプリケーションの内部を、理想的には既存のライブラリの形式で監視するための良い方法があるかどうかを知りたいです。

私のアプリケーションは非常にマルチスレッド化されており、メッセージングシステムを使用して、スレッド間および外部と通信します。私の目標は、送信されるメッセージの種類、頻度などを監視することです。

また、1分ごとに生成されるスレッドの数、呼び出される新規/削除の量、アプリケーションのより具体的な側面など、より一般的な方法で他の統計が存在する可能性もあります。あなたはそれに名前を付けます。

すばらしいのは、Google Chromeの「内部ページ」のようなものです。netやchrome:// traceingのようです、コマンドライン形式です。

私のアプリの特異性に対応するのに十分な汎用性のあるライブラリがあれば、それは素晴らしいことです。
そうでなければ、私はその仕事をする小さなクラスを実装する準備ができていますが、どこから始めればよいのかわかりません。最も重要なことは、パフォーマンスに影響を与えないように、コードがあまり干渉しないようにすることだと思います。

あなたたちはこの問題についていくつかの指針を持っていますか?

編集:私のアプリケーションはLinux上で、組み込み環境で実行されますが、残念ながらValgrindではサポートされていません:(

4

7 に答える 7

3

コードでは、インクリメントされるカウンターを維持することをお勧めします。カウンターは、staticクラスメンバーまたはグローバルにすることができます。クラスを使用してカウンターを定義する場合は、コンストラクターに、名前とともに単一のリポジトリーにカウンターを登録させることができます。次に、リポジトリを参照して、カウンタを照会およびリセットできます。

struct Counter {
    unsigned long c_;
    unsigned long operator++ () { return ++c_; }
    operator unsigned long () const { return c_; }
    void reset () { unsigned long c = c_; ATOMIC_DECREMENT(c_, c); }
    Counter (std::string name);
};

struct CounterAtomic : public Counter {
    unsigned long operator++ () { return ATOMIC_INCREMENT(c_, 1); }
    CounterAtomic (std::string name) : Counter(name) {}
};

ATOMIC_INCREMENTカウンターをアトミックにインクリメントするプラットフォーム固有のメカニズムになります。GCCは、__sync_add_and_fetchこの目的のための組み込みを提供します。ATOMIC_DECREMENT同様で、GCCが組み込まれてい__sync_sub_and_fetchます。

struct CounterRepository {
    typedef std::map<std::string, Counter *> MapType;
    mutable Mutex lock_;
    MapType map_;
    void add (std::string n, Counter &c) {
        ScopedLock<Mutex> sl(lock_);
        if (map_.find(n) != map_.end()) throw n;
        map_[n] = &c;
    }
    Counter & get (std::string n) const {
        ScopedLock<Mutex> sl(lock_);
        MapType::const_iterator i = map_.find(n);
        if (i == map_.end()) throw n;
        return *(i->second);
    }
};

CounterRepository counterRepository;

Counter::Counter (std::string name) {
    counterRepository.add(name, *this);
}

同じカウンターが複数のスレッドによってインクリメントされることがわかっている場合は、を使用しますCounterAtomic。スレッドに固有のカウンターの場合は、を使用しますCounter

于 2012-07-06T15:44:53.763 に答える
3

実行時の統計情報の収集を実装しようとしていると思います。たとえば、送信したバイト数、実行時間、ユーザーが特定の機能をアクティブにした回数などです。

通常、さまざまなソース(ワーカースレッドなど)からのこれらのようなランタイム統計をコンパイルするために、各ソース(スレッド)に最も基本的なデータの独自のローカルカウンターをインクリメントさせますが、長い計算やそのデータの分析はまだです。

次に、メインスレッド(またはこれらの統計を分析して表示する場所)に戻り、RequestProgress各ワーカースレッドにタイプメッセージを送信します。それに応じて、ワーカースレッドはすべての基本データを収集し、おそらくいくつかの簡単な分析を実行します。このデータは、基本的な分析の結果とともに、メッセージで要求元の(メイン)スレッドに返送されProgressReportます。次に、メインスレッドはこのすべてのデータを集約し、追加の(おそらくコストのかかる)分析、フォーマット、およびユーザーへの表示またはログ記録を行います。

メインスレッドRequestProgressは、ユーザーの要求(Sキーを押したときなど)または時間間隔でこのメッセージを送信します。時間間隔が目的の場合は、通常、別の新しい「ハートビート」スレッドを実装します。このスレッドが行うのはSleep()、指定された時間だけです。その後Heartbeat、メインスレッドにメッセージを送信します。次に、メインスレッドは、統計が収集されるすべてのワーカースレッドにメッセージをHeartbeat送信することにより、このメッセージに作用します。RequestProgress

統計を収集するという行為は、かなり簡単なはずです。では、なぜこのような複雑なメカニズムなのですか?答えは2つあります。

まず、ワーカースレッドにはやるべき仕事があり、使用統計の計算はそうで​​はありません。これらのスレッドをリファクタリングして、主な目的に正統な2番目の責任を引き受けようとするのは、四角いペグを丸い穴に押し込もうとするのと少し似ています。それらはそれを行うように構築されていないので、コードは書かれることに抵抗します。

第2に、実行時の統計の計算は、あまりにも頻繁に実行しようとするとコストがかかる可能性があります。たとえば、ネットワーク上でマルチキャストデータを送信するワーカースレッドがあり、スループットデータを収集するとします。何バイト、どのくらいの期間、そして1秒あたりの平均バイト数。ワーカースレッドにこれらすべてをオンザフライで計算させることもできますが、それは多くの作業であり、そのCPU時間は、ワーカースレッドが本来の処理(マルチキャストデータの送信)を実行する方が適切です。代わりに、メッセージを送信するたびに送信したバイト数のカウンターを単純にインクリメントした場合、カウントによるスレッドのパフォーマンスへの影響は最小限に抑えられます。その後、時折に応じてRequestProgressメッセージを送信して、開始時刻と停止時刻を把握し、それを送信して、メインスレッドにすべての分割などを実行させることができます。

于 2012-07-06T16:05:43.083 に答える
1

組み込みシステムでは、一般的な手法は、「ログ」用にメモリのブロックを予約し、それを循環キューのように扱うことです。このメモリブロックを読み取ることができるコードを記述します。これは、実行時に「スナップショット」を撮るのに役立ちます。

Webで「デバッグログ」を検索します。遊ぶために使用できるいくつかのソースを表示する必要があります。私が行ったことのあるほとんどの店は、通常、自分で転がっています。

余分な不揮発性メモリがある場合は、領域を予約してそれに書き込むことができます。システムがファイルシステムをサポートするのに十分な大きさである場合、これにはファイルも含まれます。

最悪の場合、デバッグ(シリアル)ポートにデータを書き込みます。

実際のリアルタイム測定では、通常、GPIOまたはテストポイントに接続されたオシロスコープを使用し、GPIO/テストポイントにパルスを出力します。

于 2012-07-06T19:46:45.810 に答える
1

共有メモリ(POSIX、System V、mmap、または利用可能なものなら何でも)を使用します。メモリの生のブロックを配列定義にキャストすることにより、揮発性の符号なし32ビットまたは64ビット整数の固定長配列(つまり、プラットフォーム上でアトミックにインクリメントできる最大値)をそこに配置します。揮発性は原子性を取得しないことに注意してください。統計値を破壊する可能性のあるコンパイラの最適化を防ぎます。gccの__sync_add_and_fetch()や新しいC++11アトミック<>タイプなどの組み込み関数を使用します。

次に、共有メモリの同じブロックに接続し、1つまたはすべての統計を出力できる小さなプログラムを作成できます。この小さな統計リーダープログラムとメインプログラムは、配列内の各統計の位置を強制する共通のヘッダーファイルを共有する必要があります。

ここでの明らかな欠点は、カウンターの数が固定されていることです。しかし、パフォーマンスの面で打ち負かすのは難しいです。影響は、プログラムのさまざまなポイントでの整数のアトミック増分です。

于 2012-07-06T19:19:56.643 に答える
0

valgrind/callgrindをご覧ください。

プロファイリングに使用できます。これは、あなたが探しているものだと私は理解しています。実行時には機能しないと思いますが、プロセスが終了した後に生成される可能性があります。

于 2012-07-06T15:45:02.920 に答える
0

それは良い答えです、@ John Dibling!私はこれと非常によく似たシステムを持っていました。ただし、私の「stat」スレッドは1秒間に10回ワーカーにクエリを実行し、「stat」スレッドがデータを要求するたびに、このデータ(カウンターなど)にアクセスするクリティカルセクションがあり、ワーカースレッドのパフォーマンスに影響を与えました。このデータが取得されている間、ワーカースレッドがブロックされることを意味します。ワーカースレッドの負荷が高い場合、この10Hzの統計クエリがワーカーの全体的なパフォーマンスに影響を与えることが判明しました。

そこで、少し異なる統計レポートモデルに切り替えました。メインスレッドからワーカースレッドをアクティブにクエリする代わりに、基本的な統計カウンターを排他的な統計リポジトリにレポートするワーカースレッドがあり、メインスレッドからいつでもクエリできます。労働者に直接的な影響はありません。

于 2015-02-25T19:10:32.923 に答える
0

C ++ 11を使用している場合は、std ::atomic<>を使用できます。

#include <atomic>

class GlobalStatistics {
public:

    static GlobalStatistics &get() {
        static GlobalStatistics instance;
        return instance;
    }

    void incrTotalBytesProcessed(unsigned int incrBy) {
        totalBytesProcessed += incrBy;
    }

    long long getTotalBytesProcessed() const { return totalBytesProcessed; }


private:

    std::atomic_llong totalBytesProcessed;

    GlobalStatistics() { }
    GlobalStatistics(const GlobalStatistics &) = delete;
    void operator=(const GlobalStatistics &) = delete;
};
于 2015-11-24T06:40:02.843 に答える