You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

含continue分支的循环向量化:Mandelbrot集计算性能优化求助

Mandelbrot集向量化优化瓶颈求助

基础信息

  • 硬件:搭载Intel(R) Xeon(R) Gold 6240 CPU的超算
  • 编译器:icc,固定编译参数:-O3 -mavx2 -xHost -g -qopenmp-simd -qopt-report=1 -qopt-report-phase=vec
  • 约束规则:仅允许向量化优化,禁止并行化;无法修改编译参数、图像宽高(宽高均为4096的倍数,内存对齐无问题)
  • 已做优化:仅计算Mandelbrot集上半部分再复制到下半部分、为所有循环添加OpenMP SIMD指令、全循环向量化
  • 性能差距:当前代码耗时约900ms,远慢于参考方案的500ms;Advixe Profiler分析显示内循环耗时主要集中在pointsRemaining、i2和r2变量

代码实现

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstring>
#include <stdlib.h>


#include "LineMandelCalculator.h"


LineMandelCalculator::LineMandelCalculator(unsigned matrixBaseSize, unsigned limit) :
    BaseMandelCalculator(matrixBaseSize, limit, "LineMandelCalculator")
{
    data = (int *)(_mm_malloc(height * width * sizeof(int), 64));
    zReal = (float *)(_mm_malloc(width * sizeof(float), 64));
    zImag = (float *)(_mm_malloc(width * sizeof(float), 64));
    iteration = (int *)(_mm_malloc(width * sizeof(int), 64));
    calculated_reals = (float *)(_mm_malloc(width * sizeof(float), 64));


    for (int i = 0; i < width; ++i) {
        calculated_reals[i] = x_start + i * dx;
        zReal[i] = 0.0f;
        zImag[i] = 0.0f;
        iteration[i] = limit;
    }
}

LineMandelCalculator::~LineMandelCalculator() {
    _mm_free(data);
    _mm_free(zReal);
    _mm_free(zImag);
    _mm_free(iteration);
    _mm_free(calculated_reals);

    data = NULL;
    zReal = NULL;
    zImag = NULL;
    iteration = NULL;
    calculated_reals = NULL;
}

int * LineMandelCalculator::calculateMandelbrot() {
    int *pdata = data;
    int half_height = height / 2;
    float *zReal = this -> zReal;
    float *zImag = this -> zImag;
    float *calculated_reals = this -> calculated_reals;
    int * iteration = this -> iteration;
    int limit = this -> limit;
    int width = this -> width;
    float dx = (float)this -> dx;
    float dy = (float)this -> dy;

    for (int i = 0; i < half_height; i++) {
        float y = y_start + i * dy;

        #pragma omp simd simdlen(64) aligned(zReal, zImag, iteration:64)
        for (int j = 0; j < width; j++) {
            zReal[j] = calculated_reals[j];
            zImag[j] = y;
            iteration[j] = limit;
        }

        int pointsRemaining = width; 

        for (int k = 0; k < limit && pointsRemaining!=0; ++k) {
            pointsRemaining = 0; 

            #pragma omp simd simdlen(64) reduction(+:pointsRemaining) aligned(zReal, zImag, calculated_reals, iteration:64)
            for (int j = 0; j < width; j++) {
                //if(iteration[j]!=limit){
                //    continue;
                //}
                float r2 = zReal[j] * zReal[j];
                float i2 = zImag[j] * zImag[j];
                bool inside = (r2 + i2 <= 4.0f);

                if (inside)pointsRemaining ++;

                zImag[j] = 2.0f * zReal[j] * zImag[j] + y;
                zReal[j] = r2 - i2 + calculated_reals[j];

                if (!inside && iteration[j] == limit){
                    iteration[j] = k;
                }
            }
        }

        memcpy(pdata + i * width, iteration, width * sizeof(int));

        memcpy(pdata + (height - i - 1) * width, pdata + i * width, width * sizeof(int));
    }

    return data;
}

代码逻辑与核心痛点

  • 逻辑:对图像每行计算迭代次数(运行脚本指定,通常100-500次),只要行内存在未发散点,就对整行所有点执行迭代计算
  • 痛点:曾尝试添加注释中的if分支跳过已收敛点,但导致代码变慢;若能实现该分支的向量化,预计性能可大幅提升

内容的提问来源于stack exchange,提问作者ampersander

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 11:18:10