Page 2 of 4 FirstFirst 1234 LastLast
Results 11 to 20 of 36

Thread: Byte-by-byte allocated data manipulation

  1. #11

    Byte-by-byte allocated data manipulation

    All I can say is that in testing I've noticed that Dynamic arrays are much slower then pointer characters.
    [pascal]procedure RunArray(A : Array of Byte);
    var
    I : Integer;
    A : Array of byte;
    begin
    for I := 0 to Length(A) -1 do
    DoSomething(A[I]);
    end;[/pascal]

    Compared to:[pascal]procedure RunPChar(PC : PChar);
    begin
    while PC^ <> #0 do
    begin
    DoSomething(PC^);
    inc(PC);
    end;
    end;[/pascal]

    I'll grant that the Length calculation takes time, but in the end it doesn't explain the difference. Of course if you really want to get apples to apples then you need something closer to the following (where the array is still slower due to the need to calculate the offset each time):

    [pascal]procedure RunArray(A : Array of Byte; l : Integer);
    var
    I : Integer;
    A : Array of byte;
    begin
    for I := 0 to l-1 do
    DoSomething(A[I]);
    end;[/pascal]

    Compared to:[pascal]procedure RunPChar(PC : PChar; l : Integer);
    var
    i : Integer;
    begin
    for I := 0 to l-1 do
    begin
    DoSomething(PC^);
    inc(PC);
    end;
    end;[/pascal]

    The reason for the speed difference (as I sated just before the 2nd code blocks) is that any time you access a dynamic (or static) array the offsets need to be calculated. With a PChar the inc takes care of movement and no calculation is needed to determine offset.

    One way around this would be to keep a pointer into the array and increment that pointer. But then, your back to using pointer math and why not just use PChar's to start with.

  2. #12

    Byte-by-byte allocated data manipulation

    The correct pendant to [...]
    Edit: Deleted my code. Never mind

    As you stated: You need to get a new adress every cycle.
    Thats not a problem of the delphi dynamic array!
    If you would do "somePchar[i]" every iteration (either in C or FPC)
    it would be equally slow.

    However: PChars are slow, because you need to calculate lengths
    very often (for about every operation), its hard to access specific
    elements (if you are using delphi) and: If you merely forget one 0 then
    your array is busted and you program will go nuts.

    But as far as normal arrays (not strings) are concerned:
    - The point with the specific element stays.

    If you need top-performance you can also iterate through a dynamic
    array via pointer. Thats no drawback - while enjoying all features
    (like easy resizing; it needs at least some complicated reallocation for
    pure pointer-"arrays").


    So to bottomline it:
    There is no speed difference in accessing pointers or dynamic arrays.
    someArray[i] is the very same as (somePointer+i)^

  3. #13

    Byte-by-byte allocated data manipulation

    Thats why I added in the 2nd block's of code. Notice I said I wasn't comparing apples to apples in the first.

    If your using a working pointer then your back to pointer math and are basically working with PChars (when dealing with bytes). No sense in actually creating an array and having the extra overhead at that point, instead just allocate the PChar and go. Granted your only talking a SizeOf(SizeInt) difference, but if you have a few 1000 instances that SizeOf adds up quickly.

    When I created my generic parser and lexer libraries I spent a lot of time performing tests to see what the fastest method to iterate strings was, PChar always won in size and speed comparisons.

    The other nice thing is that AnsiString to PChar casting is lossless where Array to AnsiString or AnsiString to Array causes a mem copy.

    I will say that arrays win if you are doing something as follows:[pascal]procedure LoadDataFile(FromFile : AnsiString);
    var
    fs : TFileStream;
    iCount : Integer;
    begin
    fs := TFileStream.Create(FromFile, fmOpenRead);
    try
    iCount := fs.Size div SizeOf(TMyRecordType);
    SetLength(Data, iCount);
    fs.Read(Data[0], iCount * SizeOf(TMyRecordType);
    finally
    fs.Free;
    end;
    end;[/pascal]
    (that code isn't tested at all LOL)

    This is mainly due to the fact that using direct blocks of memory (PChar or pointer) you will have to perform a copy with block reads instead of a single direct read from the origin. Behind the scenes, FPC (and Delphi for that matter) handle these block reads for you in the scenario above and use pointer math to move through the target.

    [Edit] PS: Your retort proves my point, any time you can move to pointer access over indexed access its faster. You can go back through everything I posted and change it to Pointer instead of PChar and its the same thing. I'm speaking against indexed access when compared to pointer access. In the end, I believe, we are both saying pointer access is faster than indexed access.

  4. #14

    Byte-by-byte allocated data manipulation

    lets take it to the peak:

    [pascal]
    var
    a: array of integer;
    i: integer;
    begin
    setlength(a, 20);
    for i := a[0] to a[19] do doSomething(i);
    end.
    [/pascal]

    ... we calculate 1 offset only.
    Ok. Now tried it ... doesn't work, sadly

    Yes, we are indeed saying the same. The main thing I want to state
    is that a[i] and (a+i)^ is the same.
    Of course calculating 20 offsets is slower than calculating 1 and
    then increment the pointer.

  5. #15

    Byte-by-byte allocated data manipulation

    Quote Originally Posted by jdarling
    [pascal]procedure RunArray(A : Array of Byte);
    var
    I : Integer;
    A : Array of byte;
    begin
    for I := 0 to Length(A) -1 do
    DoSomething(A[I]);
    end;[/pascal]
    Two problems with above code:

    1. A declared twice so it won't compile in Delphi
    2. The parameter is passed by value, which means it is copied every time.

    This version which should be as fast as pchar:

    [pascal]procedure RunArray(const A : Array of Byte);
    var
    I : Integer;
    begin
    for I := 0 to Length(A) -1 do
    DoSomething(A[I]);
    end;[/pascal]
    ZGameEditor - Develop 64kb games for Windows.
    Thrust for Vectrex - ROM-file and 6809 source code.

  6. #16

    Byte-by-byte allocated data manipulation

    @ VilleK, its slightly slower.

    [pascal]
    uses windows;

    procedure Arr(var a: array of integer);
    var
    wrkPointer: ^integer;
    i: integer;
    begin
    wrkPointer := a;
    for i:=0 to high(a) do
    begin
    wrkPointer^ := wrkPointer^ div 3;
    inc(wrkPointer);
    end;
    end;

    procedure Arr2(var a: array of integer);
    var
    i: integer;
    begin
    for i:=0 to high(a) do a[i] := a[i] div 3;
    end;

    var
    a: array of integer;
    i: integer;
    t1,t2,fq: int64;
    begin
    setlength(a, 100000);
    for i:=0 to high(a) do a[i] := random($FFFFFFFF);

    QueryPerformanceFrequency(fq);
    QueryPerformanceCounter(t1);
    Arr(a);
    //Arr2(a);
    QueryPerformanceCounter(t2);

    writeln(((t2-t1)/fq):8:;
    end.
    [/pascal]

    Results:
    0.00022s (for Arr)
    0.00026s (for Arr2)

    I don't know if this plus in performance really justifies the means.

  7. #17

    Byte-by-byte allocated data manipulation

    Sadly, Delphi can't optimize sequential access to an array (doesn't matter dynamic one or not), so pointer increment works faster in that case. But random/indirect access performance is equal.
    Main benefit of dynamic arrays is safety. With pointer math you can easily violate array bounds. And this may emerge as a weird, difficult to catch bug.
    With dynamic arrays there is range checking in debug builds which actually saves a lot of debugging time.
    So pointer math is sensible only in time-critical parts of code and as an optimization over dynamic array-based code.

    UPD:
    waran, the line
    Code:
    wrkPointer &#58;= @a;
    is incorrect. There should be:
    Code:
    wrkPointer &#58;= @a&#91;0&#93;;
    But performance will be the same of course.

  8. #18

    Byte-by-byte allocated data manipulation

    Or just "a" without @.
    Corrected it.

  9. #19
    Co-Founder / PGD Elder WILL's Avatar
    Join Date
    Apr 2003
    Location
    Canada
    Posts
    6,107
    Blog Entries
    25

    Byte-by-byte allocated data manipulation

    Ok fair enough guys. But can anyone confirm my follow-up question?

    Quote Originally Posted by WILL
    I also want to manipulate it then feed it back. I imagine I'd be able to assign it back to the Byte/Word pointer in the same manner?
    What I mean is; so far I understand that I can read the value of a sample in an allocation of memory using the byte and word pointers, but would I be able to then assign values back to the allocated memory using these same pointers?

    [pascal]var
    Bob: byte;
    Chuck: ^byte;

    Chuck := @MemoryAddress^; // Get Address I need
    Bob := Chuck^; // Read data I need
    inc(Bob); // Mess with it...
    Chuck^ := Bob; // Stick it back in there how I need it![/pascal]

    Further; if this will do the trick, are there any issues that would help to know?

    Also can I easily extract the data and the inser it in as a diferent format? ie. read a signed byte/word value and then feed back an unsigned byte/word value?


    I realize that these questions might seem a bit 'simple', but it's been a while and I'm way out of practice. Thanks!
    Jason McMillen
    Pascal Game Development
    Co-Founder





  10. #20

    Byte-by-byte allocated data manipulation

    Try keep variable types the same on source and destination. Extra type conversions takes time and makes errors possible. Especially if you have
    [pascal]var
    source: smallint;
    dest: word;
    begin
    source:=-1;
    dest:=source; // Now dest would be something over 30000 i guess
    // or vice versa, unsigned to signed can result in number go negative
    // or larger type to small type can make the value looping like with mod
    end;[/pascal]
    You know what i mean...

    And your code seems valid.

Page 2 of 4 FirstFirst 1234 LastLast

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •