9

最近、SonarQube サーバーを最新バージョン (5.3) にアップグレードし、すべてのプラグインをアップグレードしました。サーバーは、現時点では、Visual Studio Team Services (以前は Visual Studio Online) によってビルドされた C# プロジェクトの 1 つのビルドのみを監視します。

最初は、すべてうまくいきました(別の質問で説明する長年の問題は別として)。しかし、しばらくすると、データを SQ にプッシュしようとすると、次のようなエラーが発生し始めました。

ERROR: Error during Sonar runner execution
org.sonar.runner.impl.RunnerException: Unable to execute Sonar
    at org.sonar.runner.impl.BatchLauncher$1.delegateExecution(BatchLauncher.java:91)
    at org.sonar.runner.impl.BatchLauncher$1.run(BatchLauncher.java:75)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.sonar.runner.impl.BatchLauncher.doExecute(BatchLauncher.java:69)
    at org.sonar.runner.impl.BatchLauncher.execute(BatchLauncher.java:50)
    at org.sonar.runner.api.EmbeddedRunner.doExecute(EmbeddedRunner.java:102)
    at org.sonar.runner.api.Runner.execute(Runner.java:100)
    at org.sonar.runner.Main.executeTask(Main.java:70)
    at org.sonar.runner.Main.execute(Main.java:59)
    at org.sonar.runner.Main.main(Main.java:53)
Caused by: java.lang.IllegalStateException: Can't create measure for line 47 for file '[PATH]/[FILENAME].cs' with 45 lines
    at org.sonar.batch.sensor.coverage.CoverageExclusions.validateMaxLine(CoverageExclusions.java:158)
    at org.sonar.batch.sensor.coverage.CoverageExclusions.validate(CoverageExclusions.java:129)
    at org.sonar.batch.deprecated.DeprecatedSensorContext.saveMeasure(DeprecatedSensorContext.java:204)
    at org.sonar.plugins.dotnet.tests.CoverageReportImportSensor.analyze(CoverageReportImportSensor.java:78)
    at org.sonar.plugins.dotnet.tests.CoverageReportImportSensor.analyse(CoverageReportImportSensor.java:59)
    at org.sonar.batch.phases.SensorsExecutor.executeSensor(SensorsExecutor.java:58)
    at org.sonar.batch.phases.SensorsExecutor.execute(SensorsExecutor.java:50)
    at org.sonar.batch.phases.PhaseExecutor.execute(PhaseExecutor.java:98)
    at org.sonar.batch.scan.ModuleScanContainer.doAfterStart(ModuleScanContainer.java:185)
    at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:132)
    at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:117)
    at org.sonar.batch.scan.ProjectScanContainer.scan(ProjectScanContainer.java:243)
    at org.sonar.batch.scan.ProjectScanContainer.scanRecursively(ProjectScanContainer.java:238)
    at org.sonar.batch.scan.ProjectScanContainer.scanRecursively(ProjectScanContainer.java:236)
    at org.sonar.batch.scan.ProjectScanContainer.doAfterStart(ProjectScanContainer.java:228)
    at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:132)
    at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:117)
    at org.sonar.batch.task.ScanTask.execute(ScanTask.java:55)
    at org.sonar.batch.task.TaskContainer.doAfterStart(TaskContainer.java:86)
    at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:132)
    at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:117)
    at org.sonar.batch.bootstrap.GlobalContainer.executeTask(GlobalContainer.java:122)
    at org.sonar.batch.bootstrapper.Batch.executeTask(Batch.java:119)
    at org.sonar.batch.bootstrapper.Batch.execute(Batch.java:79)
    at org.sonar.runner.batch.IsolatedLauncher.execute(IsolatedLauncher.java:48)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.sonar.runner.impl.BatchLauncher$1.delegateExecution(BatchLauncher.java:87)
    ... 9 more

プラグイン ( sonar - dotnet -tests-library) の 1 つのコードを変更し、サーバー上にビルドされたファイル。.NET の専門家として、これを機能させるために他の人々の Java ライブラリを変更する必要がなくても構いません ;)

これは問題の解決策ですか、それともこれを引き起こしている可能性のあるものは他にありますか? 現時点では、SonarQube へのデータのプッシュを停止しています。これは残念です...


注: この回答は、ループ順序から最高のパフォーマンスを引き出す方法や並列化する方法に関するものではありません。これは、いくつかの理由により次善であると考えているためです。代わりに、順序を改善する (および並列化する) 方法についてアドバイスを試みます。

ループ順

通常、OpenMP は複数の CPU に作業を分散するために使用されます。したがって、必要なデータと情報の転送量を最小限に抑えながら、各スレッドのワークロードを最大化する必要があります。

  1. 2 番目のループではなく、最も外側のループを並列に実行したい。したがって、r_matrix結果マトリックスに書き込むときの競合状態を避けるために、インデックスの 1 つを外側のループ インデックスとして使用する必要があります。

  2. 次に、メモリ ストレージの順序で行列をトラバースする必要があります (最初の添え字インデックスではなく、2 番目に高速に変化するインデックスを使用します)。

次のループ/インデックスの順序で両方を実現できます。

for i = 0 to a_rows
  for k = 0 to a_cols
    for j = 0 to b_cols
      r[i][j] = a[i][k]*b[k][j]

どこ

  • jiはまたはより速く変化kし、より速くk変化しますi
  • iは結果行列の添え字であり、iループは並列に実行できます

そのように再配置するmultiply_matrices_KIJと、すでにかなりのパフォーマンスが向上しています。

私はいくつかの短いテストを行い、タイミングを比較するために使用したコードは次のとおりです。

template<class T>
void mm_kij(T const * const matrix_a, std::size_t const a_rows, 
  std::size_t const a_cols, T const * const matrix_b, std::size_t const b_rows, 
  std::size_t const b_cols, T * const matrix_r)
{
  for (std::size_t k = 0; k < a_cols; k++)
  {
    for (std::size_t i = 0; i < a_rows; i++)
    {
      for (std::size_t j = 0; j < b_cols; j++)
      {
        matrix_r[i*b_cols + j] += 
          matrix_a[i*a_cols + k] * matrix_b[k*b_cols + j];
      }
    }
  }
}

あなたのmultiply_matrices_KIJ()機能を模倣する

template<class T>
void mm_opt(T const * const a_matrix, std::size_t const a_rows, 
  std::size_t const a_cols, T const * const b_matrix, std::size_t const b_rows, 
  std::size_t const b_cols, T * const r_matrix)
{
  for (std::size_t i = 0; i < a_rows; ++i)
  { 
    T * const r_row_p = r_matrix + i*b_cols;
    for (std::size_t k = 0; k < a_cols; ++k)
    { 
      auto const a_val = a_matrix[i*a_cols + k];
      T const * const b_row_p = b_matrix + k * b_cols;
      for (std::size_t j = 0; j < b_cols; ++j)
      { 
        r_row_p[j] += a_val * b_row_p[j];
      }
    }
  }
}

上記の命令を実行します。

Intel i5-2500k での 2 つの 2048x2048 行列乗算にかかる時間

  • mm_kij(): 6.16706秒。

  • mm_opt(): 2.6567 秒。

指定された順序により、結果マトリックスへの書き込み時に競合状態を発生させることなく、外部ループの並列化も可能になります。

template<class T>
void mm_opt_par(T const * const a_matrix, std::size_t const a_rows, 
  std::size_t const a_cols, T const * const b_matrix, std::size_t const b_rows, 
  std::size_t const b_cols, T * const r_matrix)
{
#if defined(_OPENMP)
  #pragma omp parallel
  {
    auto ar = static_cast<std::ptrdiff_t>(a_rows);
    #pragma omp for schedule(static) nowait
    for (std::ptrdiff_t i = 0; i < ar; ++i)
#else
    for (std::size_t i = 0; i < a_rows; ++i)
#endif
    {
      T * const r_row_p = r_matrix + i*b_cols;
      for (std::size_t k = 0; k < b_rows; ++k)
      {
        auto const a_val = a_matrix[i*a_cols + k];
        T const * const b_row_p = b_matrix + k * b_cols;
        for (std::size_t j = 0; j < b_cols; ++j)
        {
          r_row_p[j] += a_val * b_row_p[j];
        }
      }
    }
#if defined(_OPENMP)
  }
#endif
}

各スレッドが個々の結果行に書き込む場所

Intel i5-2500k (4 OMP スレッド) での 2 つの 2048x2048 行列乗算にかかる時間

  • mm_kij(): 6.16706秒。

  • mm_opt(): 2.6567 秒。

  • mm_opt_par(): 0.968325 秒。

完全なスケーリングではありませんが、シリアルコードよりも高速に開始できます。

4

2 に答える 2

3

Visual Studio 2015 に同梱されているコード カバレッジ ツールに問題があるようです。この問題は、Visual Studio 2015 Update 3 で修正されるはずです。

ホストされたエージェントも、Update 3 がリリースされた直後に更新する必要があります。TFS ビルド チームは、これに非常に迅速に対応しています。ホストされたエージェントで利用可能なソフトウェアのリストについては、こちらを参照してください。

それまでの回避策:

  1. VS Test ビルド タスクのオプションを無効にするなどして、コード カバレッジ ファイルを生成しないでください。
  2. 一部のユーザーは、VS 2013 では問題が発生しないと報告しているため、VS 2015 を使用する代わりに、VS 2013 でビルドおよび/またはテストすることをお勧めします。
于 2016-06-09T10:57:07.690 に答える
1

私にとってこれは、以前のビルドの OpenCover レポートが Jenkins に取り残されていたためであることが判明しました。

それらがすべて削除されたことを確認すると、問題は解消されました。複数のレポートがあるということは、ファイルを複数回処理しようとしていたことを意味していると思います。

于 2016-06-08T06:45:08.817 に答える