【问题标题】:Interpreting visual studio profiler, is this subtraction slow? Can I make all this any faster?解释visual studio profiler,这个减法慢吗?我可以让这一切更快吗?
【发布时间】:2021-11-15 09:59:36
【问题描述】:

我是第一次使用 Visual Studio 分析器,我正在尝试解释结果。看左边的百分比,我发现这个减法的时间成本有点奇怪:

代码的其他部分包含更复杂的表达式,例如:

即使是简单的乘法也似乎比减法更快:

其他乘法需要更长的时间,我真的不明白为什么,像这样:

所以,我想我的问题是这里是否发生了什么奇怪的事情。

复杂的表达式比减法花费的时间更长,有些表达式比其他类似的表达式花费的时间更长。我多次运行分析器,百分比的分布总是这样。我只是解释错了吗?

更新:

我被要求提供整个函数的配置文件,所以它就在这里,即使它有点大。我在 for 循环中运行该函数 1 分钟并获得了 50k 个样本。该函数包含一个双循环。为了方便起见,我首先包含文本,然后是分析图片。请注意,文本中的代码有点更新。

 for (int i = 0; i < NUMBER_OF_CONTOUR_POINTS; i++) {

    vec4 contourPointV(contour3DPoints[i], 1);
    float phi = angles[i];

    float xW = pose[0][0] * contourPointV.x + pose[1][0] * contourPointV.y + contourPointV.z * pose[2][0] + pose[3][0];
    float yW = pose[0][1] * contourPointV.x + pose[1][1] * contourPointV.y + contourPointV.z * pose[2][1] + pose[3][1];
    float zW = pose[0][2] * contourPointV.x + pose[1][2] * contourPointV.y + contourPointV.z * pose[2][2] + pose[3][2];

    float x = -G_FU_STRICT * xW / zW;
    float y = -G_FV_STRICT * yW / zW;
    x = (x + 1) * G_WIDTHo2;
    y = (y + 1) * G_HEIGHTo2;
    y = G_HEIGHT - y;



    phi -= extraTheta;
    if (phi < 0)phi += CV_PI2;
    int indexForTable = phi * oneKoverPI;
    //vec2 ray(cos(phi), sin(phi));
    vec2 ray(cos_pre[indexForTable], sin_pre[indexForTable]);
    vec2 ray2(-ray.x, -ray.y);
    float outerStepX = ray.x * step;
    float outerStepY = ray.y * step;
    cv::Point2f outerPoint(x + outerStepX, y + outerStepY);
    cv::Point2f innerPoint(x - outerStepX, y - outerStepY);
    cv::Point2f contourPointCV(x, y);
    cv::Point2f contourPointCVcopy(x, y);

    bool cut = false;
    if (!isInView(outerPoint.x, outerPoint.y) || !isInView(innerPoint.x, innerPoint.y)) {
        cut = true;
    }
    bool outside2 = true; bool outside1 = true;

    if (cut) {
        outside2 = myClipLine(contourPointCV.x, contourPointCV.y, outerPoint.x, outerPoint.y, G_WIDTH - 1, G_HEIGHT - 1);
        outside1 = myClipLine(contourPointCVcopy.x, contourPointCVcopy.y, innerPoint.x, innerPoint.y, G_WIDTH - 1, G_HEIGHT - 1);
    }


    myIterator innerRayMine(contourPointCVcopy, innerPoint);
    myIterator outerRayMine(contourPointCV, outerPoint);

    if (!outside1) {
        innerRayMine.end = true;
        innerRayMine.prob = true;
    }
    if (!outside2) {
        outerRayMine.end = true;
        innerRayMine.prob = true;
    }



    vec2 normal = -ray;
    float dfdxTerm = -normal.x;
    float dfdyTerm = normal.y;
    vec3 point3D = vec3(xW, yW, zW);
    cv::Point contourPoint((int)x, (int)y);



    float Xc = point3D.x; float Xc2 = Xc * Xc; float Yc = point3D.y; float Yc2 = Yc * Yc; float Zc = point3D.z; float Zc2 = Zc * Zc;
    float XcYc = Xc * Yc; float dfdxFu = dfdxTerm * G_FU; float dfdyFv = dfdyTerm * G_FU; float overZc2 = 1 / Zc2; float overZc = 1 / Zc;
    pixelJacobi[0] = (dfdyFv * (Yc2 + Zc2) + dfdxFu * XcYc) * overZc2;
    pixelJacobi[1] = (-dfdxFu * (Xc2 + Zc2) - dfdyFv * XcYc) * overZc2;
    pixelJacobi[2] = (-dfdyFv * Xc + dfdxFu * Yc) * overZc;
    pixelJacobi[3] = -dfdxFu * overZc;
    pixelJacobi[4] = -dfdyFv * overZc;
    pixelJacobi[5] = (dfdyFv * Yc + dfdxFu * Xc) * overZc2;


    float commonFirstTermsSum = 0;
    float commonFirstTermsSquaredSum = 0;

    int test = 0;
    while (!innerRayMine.end) {

        test++;
        cv::Point xy = innerRayMine.pos(); innerRayMine++;
        int x = xy.x;
        int y = xy.y;
        float dx = x - contourPoint.x;
        float dy = y - contourPoint.y;
        vec2 dxdy(dx, dy);

        float raw = -glm::dot(dxdy, normal);
        float heavisideTerm = heaviside_pre[(int)raw * 100 + 1000];
        float deltaTerm = delta_pre[(int)raw * 100 + 1000];


        const Vec3b rgb = ante[y * 640 + x];
        int red = rgb[0]; int green = rgb[1]; int blue = rgb[2];
        red = red >> 3; red = red << 10; green = green >> 3; green = green << 5; blue = blue >> 3;
        int colorIndex = red + green + blue;

        pF = pFPointer[colorIndex];
        pB = pBPointer[colorIndex];
        float denAsMul = 1 / (pF + pB + 0.000001);
        pF = pF * denAsMul;

        float pfMinusPb = 2 * pF - 1;
        float denominator = heavisideTerm * (pfMinusPb)+pB + 0.000001;
        float commonFirstTerm = -pfMinusPb / denominator * deltaTerm;

        commonFirstTermsSum += commonFirstTerm;
        commonFirstTermsSquaredSum += commonFirstTerm * commonFirstTerm;

    }
}

【问题讨论】:

  • 需要摩尔上下文。减法通常很便宜,所以我们需要看看减法发生了什么,例如,相对于其余代码,它被调用了多少次。
  • @user4581301 抱歉,正如我所说,这是我第一次进行分析,我不确定我需要提供多少。所有这些都在一个特定的函数中,该函数占用了 50% 的分析。该函数很长,我让分析器运行了大约一分钟,在一个大的 for 循环中运行该函数。由于在问题中包含这里是一个很长的功能,我可以提供什么以便这里的人们可以提供帮助?
  • 我们需要函数的上下文(所以至少要分析的代码块,以及相关变量的类型)。函数执行多少次?什么是编译器优化标志(如果有)?目标架构/处理器是什么?
  • @JérômeRichard 当我让分析器工作时,我会尝试添加更多信息。由于常见错误“当前过滤器集中没有数据”,它突然停止工作。
  • @JérômeRichard 关于优化我刚刚在 c/c++ 优化设置中激活了 O2。至于架构/处理器,如果我理解正确的话,架构是 x64,我使用的是 i5 10300h 的一个内核。

标签: c++ performance profiling


【解决方案1】:

Visual Studio 采样配置文件:它经常中断执行并记录指令指针的值;然后它将它映射到源并计算命中该线的频率。

这几乎没有问题:并不总是能够确定优化代码中哪一行产生了特定的汇编指令。

我使用的一个技巧是将感兴趣的代码移动到一个单独的函数中,并使用__declspec(noinline) 声明它。

在您的示例中,您确定减法的执行次数与乘法的执行次数一样多吗?后面乘法的区别我会比较疑惑(0.39%0.53%

更新:

我相信以下几行:

float phi = angles[i];

phi -= extraTheta;

在汇编中一起移动,获得angles[i] 所花费的时间被添加到该减法行中。

【讨论】:

  • 这澄清了一些事情。使用 declspec 我将获得什么?当我再次进行分析时,我将尝试返回更多详细信息。由于常见错误“当前过滤器集中没有数据”,它突然停止工作。
  • 有趣。 modern processors还有一个重要因素:指令可以并行执行。结果,某些线路可能比其他线路“慢”,因为它们受延迟限制并且位于关键路径上。因此,问题是:视觉工作室使用什么指标来选择指令比其他指标“慢”。除此之外,我对sin+cos 调用有点困惑:它们被标记为仅比减法慢 50%,而三角函数通常非常昂贵。这只是一个抽样问题?
  • @JohnKatsantas noinline 指示编译器不要在调用站点内联函数,因此可以信任该函数中的所有命中。
  • @VladFeinstein 减法在第一个循环中,而一些乘法在嵌套循环中。我用大部分功能更新了问题,你可以检查一下。
  • @JohnKatsantas请看我的更新
猜你喜欢
  • 2017-11-06
  • 2011-11-03
  • 1970-01-01
  • 1970-01-01
  • 2013-11-02
  • 1970-01-01
  • 1970-01-01
  • 2020-07-01
  • 1970-01-01
相关资源
最近更新 更多