MATLAB执行时间增加

时间:2014-08-07 20:55:45

标签: matlab optimization

这是我的代码。目的是我将Wireshark捕获保存到特别格式化的文本文件中。 MATLAB代码应该通过数据包,为不同的协议剖析它们,然后根据这些协议制作表格。我目前已经为ETHERNET / IP / UDP / MODBUS编程了。在这种情况下,它会在每次遇到新的寄存器值时在MBTable中创建一个列,并且每次遇到对该寄存器值的更改时,它都会更新表中该行的值。 MBTable的第一列是时间,寄存器从第二列开始。

MBTable预先分配到超过100,000行(nol非常大),在执行此代码之前有10列。我正在拉入表中的文件的实际数据大约有10,000行和4列,代码执行速度很慢,我必须停止它。 tic / toc值每1000行计算一次,并且每次迭代都会以指数方式继续增加。它是一个很大的循环,但是我无法看到任何东西在增长的方式会导致它在每次迭代时运行得更慢。

所有变量都被初始化(左侧是为了减少代码量)。 变量eth,eth.ip,eth.ip.udp和eth.ip.udp.modbus都是struct的类型,eth.header和eth.ip.header。 WSID是先前打开的.txt文件中的文件ID。

MBTable = zeros(nol,10);
tval = tic;
while not(feof(WSID))
    packline = packline + 1;
    fl = fl + 1;

    %Get the next line from the file
    MBLine = fgetl(WSID);
    %Make sure line is not blank or short
    if length(MBLine) >= 3
        %Split the line into 1. Line no, 2. Data, 3. ASCII
        %MBAll = strsplit(MBLine,' ');
        %First line of new packet, if headers included
        if strcmp(MBLine(1:3),'No.')
            newpack = true;
            newtime = false;
            newdata = false;
            stoppack = false;
            packline = 1;
        end
        %If packet has headers, 2nd line contains timestamp
        if newpack
            Ordered = false;
            if packline == 2;
                newtime = true;
                %MBstrs = strsplit(MBAll{2},' ');
                packno = int32(str2double(MBLine(1:8)));
                t = str2double(MBLine(9:20));

                et = t - lastt;
                if lastt > 0 && et > 0
                    L = L + 1;
                    MBTable(L,1) = t;
                end
                %newpack = false;
            end
            if packline > 3              
                    dataline = int16(str2double(MBLine(1:4)));
                    packdata = strcat(packdata,MBLine(7:53));
            end
        end

    else
        %if t >= st

        if packline > 3
            stoppack = true;
            newpack = false;
        end
        if stoppack
            invalid = false;
            %eth = struct;

            eth.pack = packdata(~isspace(packdata));
            eth.length = length(eth.pack);

            %Dissect the packet data
            eth.stbyte = 1;
            eth.ebyte = eth.length;
            eth.header.stbyte = 1;
            eth.header.ebyte = 28;
            %Ethernet Packet Data
            eth.header.pack = eth.pack(eth.stbyte:eth.stbyte+27);
            eth.header.dest = eth.header.pack(eth.header.stbyte:eth.header.stbyte + 11);
            eth.header.src = eth.header.pack(eth.header.stbyte + 12:eth.header.stbyte + 23);
            eth.typecode = eth.header.pack(eth.header.stbyte + 24:eth.header.ebyte);

            if strcmp(eth.typecode,'0800')

                eth.type = 'IP';
                %eth.ip = struct;
                %IP Packet Data
                eth.ip.stbyte = eth.header.ebyte + 1;
                eth.ip.ver = eth.pack(eth.ip.stbyte);
                %IP Header length
                eth.ip.header.length = 4*int8(str2double(eth.pack(eth.ip.stbyte+1)));
                eth.ip.header.ebyte = eth.ip.stbyte + eth.ip.header.length - 1;
                %Differentiated Services Field
                eth.ip.DSF = eth.pack(eth.ip.stbyte + 2:eth.ip.stbyte + 3);
                %Total IP Packet Length
                eth.ip.length = hex2dec(eth.pack(eth.ip.stbyte+4:eth.ip.stbyte+7));
                eth.ip.ebyte = eth.ip.stbyte + max(eth.ip.length,46) - 1;
                eth.ip.pack = eth.pack(eth.ip.stbyte:eth.ip.ebyte);
                eth.ip.ID = eth.pack(eth.ip.stbyte+8:eth.ip.stbyte+11);
                eth.ip.flags = eth.pack(eth.ip.stbyte+12:eth.ip.stbyte+13);
                eth.ip.fragoff = eth.pack(eth.ip.stbyte+14:eth.ip.stbyte+15);
                %Time to Live
                eth.ip.ttl = hex2dec(eth.pack(eth.ip.stbyte+16:eth.ip.stbyte+17));
                eth.ip.typecode = eth.pack(eth.ip.stbyte+18:eth.ip.stbyte+19);
                eth.ip.checksum = eth.pack(eth.ip.stbyte+20:eth.ip.stbyte+23);

                %eth.ip.src = eth.pack(eth.ip.stbyte+24:eth.ip.stbyte+31);

                eth.ip.src = ...
                    [num2str(hex2dec(eth.pack(eth.ip.stbyte+24:eth.ip.stbyte+25))),'.', ...
                    num2str(hex2dec(eth.pack(eth.ip.stbyte+26:eth.ip.stbyte+27))),'.', ...
                    num2str(hex2dec(eth.pack(eth.ip.stbyte+28:eth.ip.stbyte+29))),'.', ...
                    num2str(hex2dec(eth.pack(eth.ip.stbyte+30:eth.ip.stbyte+31)))];

                eth.ip.dest = ...
                    [num2str(hex2dec(eth.pack(eth.ip.stbyte+32:eth.ip.stbyte+33))),'.', ...
                    num2str(hex2dec(eth.pack(eth.ip.stbyte+34:eth.ip.stbyte+35))),'.', ...
                    num2str(hex2dec(eth.pack(eth.ip.stbyte+36:eth.ip.stbyte+37))),'.', ...
                    num2str(hex2dec(eth.pack(eth.ip.stbyte+38:eth.ip.stbyte+39)))];

                if strcmp(eth.ip.typecode,'11')
                    eth.ip.type = 'UDP';

                    eth.ip.udp.stbyte = eth.ip.stbyte + 40;
                    eth.ip.udp.src = hex2dec(eth.pack(eth.ip.udp.stbyte:eth.ip.udp.stbyte + 3));
                    eth.ip.udp.dest = hex2dec(eth.pack(eth.ip.udp.stbyte+4:eth.ip.udp.stbyte+7));
                    eth.ip.udp.length = hex2dec(eth.pack(eth.ip.udp.stbyte+8:eth.ip.udp.stbyte+11));
                    eth.ip.udp.checksum = eth.pack(eth.ip.udp.stbyte+12:eth.ip.udp.stbyte+15);
                    eth.ip.udp.protoID = eth.pack(eth.ip.udp.stbyte+20:eth.ip.udp.stbyte+23);

                    if strcmp(eth.ip.udp.protoID,'0000')
                       eth.ip.udp.proto = 'MODBUS';

                       %eth.ip.udp.modbus = struct;
                       eth.ip.udp.modbus.stbyte = eth.ip.udp.stbyte+16;
                       eth.ip.udp.modbus.transID = eth.pack(eth.ip.udp.modbus.stbyte:eth.ip.udp.modbus.stbyte+3);
                       eth.ip.udp.modbus.protoID = eth.ip.udp.protoID;
                       eth.ip.udp.modbus.length = int16(str2double(eth.pack(eth.ip.udp.modbus.stbyte + 8:eth.ip.udp.modbus.stbyte + 11)));
                       eth.ip.udp.modbus.UID = eth.pack(eth.ip.udp.modbus.stbyte + 12:eth.ip.udp.modbus.stbyte + 13);
                       eth.ip.udp.modbus.func = hex2dec(eth.pack(eth.ip.udp.modbus.stbyte + 14:eth.ip.udp.modbus.stbyte+15));
                       eth.ip.udp.modbus.register = eth.pack(eth.ip.udp.modbus.stbyte + 16: eth.ip.udp.modbus.stbyte+19);
                       %Number of words to a register, or the number of registers
                       eth.ip.udp.modbus.words = hex2dec(eth.pack(eth.ip.udp.modbus.stbyte+20:eth.ip.udp.modbus.stbyte+23));
                       eth.ip.udp.modbus.bytes = hex2dec(eth.pack(eth.ip.udp.modbus.stbyte+24:eth.ip.udp.modbus.stbyte+25));
                       eth.ip.udp.modbus.data = eth.pack(eth.ip.udp.modbus.stbyte + 26:eth.ip.udp.modbus.stbyte + 26 + 2*eth.ip.udp.modbus.bytes - 1);


                       %If func 16 or 23, loop through data/registers and add to table
                       if eth.ip.udp.modbus.func == 16 || eth.ip.udp.modbus.func == 23
                           stp = eth.ip.udp.modbus.bytes*2/eth.ip.udp.modbus.words;
                           for n = 1:stp:eth.ip.udp.modbus.bytes*2;
                              %Check for existence of register as a key?
                              if ~isKey(MBMap,eth.ip.udp.modbus.register)
                                MBCol = MBCol + 1;
                                MBMap(eth.ip.udp.modbus.register) = MBCol; 
                              end
                              MBTable(L,MBCol) = hex2dec(eth.ip.udp.modbus.data(n:n+stp-1));
                              eth.ip.udp.modbus.register = dec2hex(hex2dec(eth.ip.udp.modbus.register)+1);
                           end
                           lastt = t;
                       end

                       %If func 4, make sure it is the response, then put
                       %data into table for register column

                    elseif false

                        %need code to handle serial to UDP conversion box

                    else
                        invalid = true;
                    end

                else
                    invalid = true;
                end

            else
                invalid = true;
            end


            if ~invalid

            end
        end
        %end
    end
   %Display Progress
   if int64(fl/1000)*1000 == fl
       for x = 1:length(mess);
           fprintf('\b');
       end
       %fprintf('Lines parsed: %i',fl);
        mess = sprintf('Lines parsed: %i / %i',fl,nol);
        fprintf('%s',mess);
       %Check execution time - getting slower:
       %%{
       ext = toc(tval);
        mess = sprintf('\nExecution Time: %f\n',ext);
        fprintf('%s',mess);
       %%}
   end
end
ext = toc - exst;

更新:我更新了上面的代码以删除重载的运算符(disp和lt被替换为mess和lastt)

被要求使用分析器,所以我限制在表格中的2000行(添加&& L> = 2000到while循环)来限制执行时间,这里是分析器的最佳结果:

SGAS_Wireshark_Parser_v0p7_fulleth        1    57.110 s     9.714 s
Strcat                                 9187    29.271 s    13.598 s
Blanks                                 9187    15.673 s    15.673 s
Uigetfile                                 1    12.226 s     0.009 s
uitools\private\uigetputfile_helper       1    12.212 s     0.031 s
FileChooser.FileChooser>FileChooser.show    1  12.085 s      0.006s
...er>FileChooser.showPeerAndBlockMATLAB    1  12.056 s      0.001s
...nChooser>FileOpenChooser.doShowDialog    1  12.049 s    12.049 s
hex2dec                               44924     2.944 s     2.702 s
num2str                               16336     1.139 s     0.550 s
str2double                            17356     1.025 s     1.025 s
int2str                               16336     0.589 s     0.589 s
fgetl                                 17356     0.488 s     0.488 s
dec2hex                                6126     0.304 s     0.304 s
fliplr                                44924     0.242 s     0.242 s

它似乎是正在进行的strcat调用。我只在一行显式调用strcat。我正在做一些其他字符串操作间接调用strcat吗? 每个循环应该调用strcat相同的次数,所以我仍然不明白为什么它运行的时间越长越长......

另外,hex2dec被称为很多,但并没有真正影响时间。

但无论如何,还有其他方法我可以使用组合字符串吗?

1 个答案:

答案 0 :(得分:0)

问题在于:

字符串(MATLAB中的char数组)packdata正在调整大小并反复重新分配。这会降低这段代码的速度。我做了以下步骤:

我删除了冗余变量packdata,现在只使用eth.pack。

我预先分配了eth.pack和一对"帮助变量"通过在循环开始之前为每个运行空白ONCE来确定已知长度

eth.pack = blanks(604);
thisline = blanks(47);
smline = blanks(32);

(注意:604是基于标题+ MODBUS协议的packdata的最大可能大小)

然后我创建了一个指针变量,指向写入packdata的最后一个char的位置。

pptr = 1;

...

dataline = int16(str2double(MBLine(1:4)));

thisline = MBLine(7:53); %Always 47 characters

smline = [thisline(~isspace(thisline)),blanks(32-sum(~isspace(thisline)))]; %Always 32 Characters

eth.pack(pptr:pptr+31) = smline;

pptr = pptr + 32;

以上是在' if packline>内3'阻止代替" packdata ='声明,然后在' if stoppack' block是重置语句:

pptr = 1; %Reset Pointer

仅供参考,这并不奇怪,这带来了我的代码中的其他缺陷,我已经解决了这些缺陷,但仍需要完成。现在这不是一个大问题,因为这个循环会随着这些变化快速执行。感谢Yvon帮助我指明正确的方向。

我一直在想我的大桌子,MBTable就是问题......但它与它无关。