Понимание результатов Intel VTune - наивные вопросы

Мое приложение, которое я хочу ускорить, выполняет поэлементную обработку большого массива (около 1e8 элементов).

Процедура обработки для каждого элемента очень проста, и я подозреваю, что узким местом может быть не процессор, а пропускная способность DRAM. Поэтому я решил сначала изучить однопоточную версию.

Система: Windows 10 64-битная, 32 ГБ оперативной памяти, Intel Core i7-3770S Ivybridge 1.10 ГГц, 4 ядра, включена поддержка Hyperthreading

Анализ параллелизма

Elapsed Time:   34.425s
    CPU Time:   14.908s
        Effective Time: 14.908s
            Idle:   0.005s
            Poor:   14.902s
            Ok: 0s
            Ideal:  0s
            Over:   0s
        Spin Time:  0s
        Overhead Time:  0s
    Wait Time:  0.000s
        Idle:   0.000s
        Poor:   0s
        Ok: 0s
        Ideal:  0s
        Over:   0s
    Total Thread Count: 2
    Paused Time:    18.767s

Анализ доступа к памяти

Анализ доступа к памяти обеспечивает разное время ЦП для трех последовательных запусков на одном и том же объеме данных. Фактическое время выполнения составило около 23 секунд, как говорит анализ параллелизма.

Elapsed Time:   33.526s
    CPU Time:   5.740s
    Memory Bound:   38.3%
        L1 Bound:   10.4%
        L2 Bound:   0.0%
        L3 Bound:   0.1%
        DRAM Bound: 0.8%
            Memory Bandwidth:   36.1%
            Memory Latency: 60.4%
    Loads:  12,912,960,000
    Stores: 7,720,800,000
    LLC Miss Count: 420,000
    Average Latency (cycles):   15
    Total Thread Count: 4
    Paused Time:    18.081s

Elapsed Time:   33.011s
    CPU Time:   4.501s
    Memory Bound:   36.9%
        L1 Bound:   10.6%
        L2 Bound:   0.0%
        L3 Bound:   0.2%
        DRAM Bound: 0.6%
            Memory Bandwidth:   36.5%
            Memory Latency: 62.7%
    Loads:  9,836,100,000
    Stores: 5,876,400,000
    LLC Miss Count: 180,000
    Average Latency (cycles):   15
    Total Thread Count: 4
    Paused Time:    17.913s

Elapsed Time:   33.738s
    CPU Time:   5.999s
    Memory Bound:   38.5%
        L1 Bound:   10.8%
        L2 Bound:   0.0%
        L3 Bound:   0.1%
        DRAM Bound: 0.9%
            Memory Bandwidth:   57.8%
            Memory Latency: 37.3%
    Loads:  13,592,760,000
    Stores: 8,125,200,000
    LLC Miss Count: 660,000
    Average Latency (cycles):   15
    Total Thread Count: 4
    Paused Time:    18.228s

Насколько я понимаю Сводная страница, ситуация не очень хорошая.

В статье "Как найти узкие места в производительности доступа к памяти" говорится, что причиной является так называемое ложное совместное использование. Но я не использую многопоточность, вся обработка выполняется одним потоком.

С другой стороны, в соответствии с анализом доступа к памяти / страницей платформы DRAM пропускная способность не является узким местом.

Итак, вопросы

  1. Почему значения метрики времени ЦП различны для анализа параллелизма и анализа доступа к памяти
  2. В чем причина неправильных значений метрик памяти, особенно для L1 Bound?

Основным циклом является лямбда-функция, где

  • тасклеты: std::vector простых структур, содержащих коэффициенты для обработки данных
  • точки: сами данные, Eigen::Matrix
  • проекции: Eigen::Matrix, массив для помещения результатов обработки в

Код является:

#include <iostream>
#include <future>
#include <random>

#include <Eigen/Dense>

#include <ittnotify.h>

using namespace std;

using Vector3 = Eigen::Matrix<float, 3, 1>;
using Matrix3X = Eigen::Matrix<float, 3, Eigen::Dynamic>;

uniform_real_distribution<float> rnd(0.1f, 100.f);
default_random_engine gen;

class Tasklet {
public:
    Tasklet(int p1, int p2)
        :
        p1Id(p1), p2Id(p2), Loc0(p1)
    {
        RestDistance = rnd(gen);
        Weight_2 = rnd(gen);
    }
    __forceinline void solve(const Matrix3X& q, Matrix3X& p)
    {
        Vector3 q1 = q.col(p1Id);
        Vector3 q2 = q.col(p2Id);
        for (int i = 0; i < 0; ++i) {
            Vector3 delta = q2 - q1;
            float norm = delta.blueNorm() * delta.hypotNorm();
        }
        Vector3 deltaQ = q2 - q1;
        float dist = deltaQ.norm();
        Vector3 deltaUnitVector = deltaQ / dist;
        p.col(Loc0) = deltaUnitVector * RestDistance * Weight_2;
    }

    int p1Id;
    int p2Id;
    int Loc0;
    float RestDistance;
    float Weight_2;
};

typedef vector<Tasklet*> TaskList;

void
runTest(const Matrix3X& points, Matrix3X& projections, TaskList& tasklets)
{
    size_t num = tasklets.size();
    for (size_t i = 0; i < num; ++i) {
        Tasklet* t = tasklets[i];
        t->solve(points, projections);
    }
}

void
prepareData(Matrix3X& points, Matrix3X& projections, int numPoints, TaskList& tasklets)
{
    points.resize(3, numPoints);
    projections.resize(3, numPoints);
    points.setRandom();
    /*
    for (int i = 0; i < numPoints; ++i) {
    points.col(i) = Vector3(1, 0, 0);
    }
    */
    tasklets.reserve(numPoints - 1);
    for (int i = 1; i < numPoints; ++i) {
        tasklets.push_back(new Tasklet(i - 1, i));
    }

}

int
main(int argc, const char** argv)
{
    // Pause VTune data collection
    __itt_pause();
    cout << "Usage: <exefile> <number of points (in thousands)> <#runs for averaging>" << endl;

    int numPoints = 150 * 1000;
    int numRuns = 1;
    int argNo = 1;

    if (argc > argNo) {
        istringstream in(argv[argNo]);
        int i;
        in >> i;
        if (in) {
            numPoints = i * 1000;
        }
    }
    ++argNo;
    if (argc > argNo) {
        istringstream in(argv[argNo]);
        int i;
        in >> i;
        if (in) {
            numRuns = i;
        }
    }
    cout
        << "Running test" << endl
        << "\t NumPoints (thousands): " << numPoints / 1000. << endl
        << "\t # of runs for averaging: " << numRuns << endl;

    Matrix3X q, projections;
    TaskList tasklets;

    cout << "Preparing test data" << endl;

    prepareData(q, projections, numPoints, tasklets);

    cout << "Running test" << endl;

    // Resume VTune data collection
    __itt_resume();
    for (int r = 0; r < numRuns; ++r) {
        runTest(q, projections, tasklets);
    }
    // Pause VTune data collection
    __itt_pause();

    for (auto* t : tasklets) {
        delete t;
    }

    return 0;
}

Спасибо.

0 ответов

Другие вопросы по тегам