Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Speed difference between two functions with unknown reason

Speed difference between two functions with unknown reason

Scheduled Pinned Locked Moved C#
dockerperformancequestion
12 Posts 4 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S SimpleData

    Hi, I have two methods, which are esentially doing similar jobs but have drastic speed differences. I don't know what is causing this speed difference. Here are the methods. The first one is like 100 times faster.

    private void SaveNativeBinary(string file, long origin, long length, string opt)
    {
    SetSSVisible(StatusStrip, pbSmallPerc, true);

            FileStream fs = null;
            FileStream writer = null;
    
            try { fs = new FileStream(file, FileMode.Open, FileAccess.Read); }
            catch { throw new Exception("ERR"); }
    
            try { writer = new FileStream(opt, FileMode.Create, FileAccess.ReadWrite); }
            catch { throw new Exception("ERR"); }
    
            fs.Seek(origin, SeekOrigin.Begin);
    
    
            for (long pos = 0; pos < length; pos++)
            {
                if (pos % 204800 == 0) // 200KB'da bir güncelle
                {
                    SetSSValue(StatusStrip, pbSmallPerc, Convert.ToInt32(PercentageCalc(pos, length)) );
                    SetSSText(StatusStrip, lblStatus, "Aktarılıyor: " + BtoKB(pos).ToString() + " / " + BtoKB(length).ToString() + " KB (%" + PercentageCalc(pos, length) + ")");
                }
                writer.WriteByte((byte)fs.ReadByte());
            }
    
            fs.Close(); fs.Dispose(); writer.Close(); writer.Dispose();
            SetSSVisible(StatusStrip, pbSmallPerc, false);
        }
    

    private void AppendBinToBin(string Container, string toAppend)
    {
    SetSSVisible(StatusStrip, pbSmallPerc, true);
    FileStream fsA, fsB = null;
    long tempLength = GetFileLength(toAppend);

            try { fsA = new FileStream(Container, FileMode.Open, FileAccess.ReadWrite); }
            catch { throw new Exception("ERR"); }
    
            try { fsB = new FileStream(toAppend, FileMode.Open, FileAccess.Read); }
            catch { throw new Exception("RRR"); }
    
            try
            {
                fsA.Seek(0, SeekOrigin.End);
                for (long pos = 0; pos < fsB.Length; pos++)
                {
                    if (pos % 204800 == 0) // 200KB'da bir güncelle
                    {
                        SetSSValue( StatusStrip, pbSmallPerc, Convert.ToInt32(PercentageCalc(pos, tempLength)) );
                        SetSSText( StatusStrip, lblStatus, "Aktarılıyor: " + BtoKB(pos).ToString() + " / " + BtoKB(tempLength).ToString() + " KB (%" + PercentageCalc(pos, tempLength) + ")" );
    
    L Offline
    L Offline
    Lost User
    wrote on last edited by
    #2

    use class Stopwatch to measure the speed difference.

    S 1 Reply Last reply
    0
    • L Lost User

      use class Stopwatch to measure the speed difference.

      S Offline
      S Offline
      SimpleData
      wrote on last edited by
      #3

      I am using the Process Explorer from SysInternals and the first method creates an IO traffic with the magnitude of approx. 32MB, but the second one can't even exceed 1MB.

      1 Reply Last reply
      0
      • S SimpleData

        Hi, I have two methods, which are esentially doing similar jobs but have drastic speed differences. I don't know what is causing this speed difference. Here are the methods. The first one is like 100 times faster.

        private void SaveNativeBinary(string file, long origin, long length, string opt)
        {
        SetSSVisible(StatusStrip, pbSmallPerc, true);

                FileStream fs = null;
                FileStream writer = null;
        
                try { fs = new FileStream(file, FileMode.Open, FileAccess.Read); }
                catch { throw new Exception("ERR"); }
        
                try { writer = new FileStream(opt, FileMode.Create, FileAccess.ReadWrite); }
                catch { throw new Exception("ERR"); }
        
                fs.Seek(origin, SeekOrigin.Begin);
        
        
                for (long pos = 0; pos < length; pos++)
                {
                    if (pos % 204800 == 0) // 200KB'da bir güncelle
                    {
                        SetSSValue(StatusStrip, pbSmallPerc, Convert.ToInt32(PercentageCalc(pos, length)) );
                        SetSSText(StatusStrip, lblStatus, "Aktarılıyor: " + BtoKB(pos).ToString() + " / " + BtoKB(length).ToString() + " KB (%" + PercentageCalc(pos, length) + ")");
                    }
                    writer.WriteByte((byte)fs.ReadByte());
                }
        
                fs.Close(); fs.Dispose(); writer.Close(); writer.Dispose();
                SetSSVisible(StatusStrip, pbSmallPerc, false);
            }
        

        private void AppendBinToBin(string Container, string toAppend)
        {
        SetSSVisible(StatusStrip, pbSmallPerc, true);
        FileStream fsA, fsB = null;
        long tempLength = GetFileLength(toAppend);

                try { fsA = new FileStream(Container, FileMode.Open, FileAccess.ReadWrite); }
                catch { throw new Exception("ERR"); }
        
                try { fsB = new FileStream(toAppend, FileMode.Open, FileAccess.Read); }
                catch { throw new Exception("RRR"); }
        
                try
                {
                    fsA.Seek(0, SeekOrigin.End);
                    for (long pos = 0; pos < fsB.Length; pos++)
                    {
                        if (pos % 204800 == 0) // 200KB'da bir güncelle
                        {
                            SetSSValue( StatusStrip, pbSmallPerc, Convert.ToInt32(PercentageCalc(pos, tempLength)) );
                            SetSSText( StatusStrip, lblStatus, "Aktarılıyor: " + BtoKB(pos).ToString() + " / " + BtoKB(tempLength).ToString() + " KB (%" + PercentageCalc(pos, tempLength) + ")" );
        
        L Offline
        L Offline
        Luc Pattyn
        wrote on last edited by
        #4

        Hi, IMO the major suspect is the test in for (long pos = 0; pos < fsB.Length; pos++) which goes out and reads a property for each byte available. It may, or may not, be much better when running a release build; anyhow, I always make sure loop termination tests are as simple as possible, a local variable often does wonders. :)

        Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


        I only read code that is properly formatted, adding PRE tags is the easiest way to obtain that.


        S 1 Reply Last reply
        0
        • L Luc Pattyn

          Hi, IMO the major suspect is the test in for (long pos = 0; pos < fsB.Length; pos++) which goes out and reads a property for each byte available. It may, or may not, be much better when running a release build; anyhow, I always make sure loop termination tests are as simple as possible, a local variable often does wonders. :)

          Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


          I only read code that is properly formatted, adding PRE tags is the easiest way to obtain that.


          S Offline
          S Offline
          SimpleData
          wrote on last edited by
          #5

          Hi, I am not sure I understood your point exactly. if(pos % 204800 == 0) block is used in both cases but they still have speed differences.

          L P 2 Replies Last reply
          0
          • S SimpleData

            Hi, I am not sure I understood your point exactly. if(pos % 204800 == 0) block is used in both cases but they still have speed differences.

            L Offline
            L Offline
            Lost User
            wrote on last edited by
            #6

            The point, as I understand it, was that calling fsB.get_Length (which is what you're doing when you ask the value of fsB.Length) may secretly be doing something that takes more than a reasonable amount of time, which is true. As proof, here is the code for FileStream.Length

            public override long get_Length()
            {
            if (this._handle.IsClosed)
            {
            __Error.FileNotOpen();
            }
            if (!this.CanSeek)
            {
            __Error.SeekNotSupported();
            }
            int highSize = 0;
            int fileSize = 0;
            fileSize = Win32Native.GetFileSize(this._handle, out highSize);
            if (fileSize == -1)
            {
            int errorCode = Marshal.GetLastWin32Error();
            if (errorCode != 0)
            {
            __Error.WinIOError(errorCode, string.Empty);
            }
            }
            long num4 = (highSize << 0x20) | ((long) ((ulong) fileSize));
            if ((this._writePos > 0) && ((this._pos + this._writePos) > num4))
            {
            num4 = this._writePos + this._pos;
            }
            return num4;
            }

            Win32Native.GetFileSize uses P/Invoke to GetFileSize in kernel32.dll Solution: store the length in a local variable (like Luc said)

            L S 2 Replies Last reply
            0
            • S SimpleData

              Hi, I am not sure I understood your point exactly. if(pos % 204800 == 0) block is used in both cases but they still have speed differences.

              P Offline
              P Offline
              Pete OHanlon
              wrote on last edited by
              #7

              Luc is talking about your use of fsB.Length, which is a property that you get every time. He's suggesting that you should store this and then work with that instead of fsB.Length in the loop.

              "WPF has many lovers. It's a veritable porn star!" - Josh Smith

              As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.

              My blog | My articles | MoXAML PowerToys | Onyx

              1 Reply Last reply
              0
              • L Lost User

                The point, as I understand it, was that calling fsB.get_Length (which is what you're doing when you ask the value of fsB.Length) may secretly be doing something that takes more than a reasonable amount of time, which is true. As proof, here is the code for FileStream.Length

                public override long get_Length()
                {
                if (this._handle.IsClosed)
                {
                __Error.FileNotOpen();
                }
                if (!this.CanSeek)
                {
                __Error.SeekNotSupported();
                }
                int highSize = 0;
                int fileSize = 0;
                fileSize = Win32Native.GetFileSize(this._handle, out highSize);
                if (fileSize == -1)
                {
                int errorCode = Marshal.GetLastWin32Error();
                if (errorCode != 0)
                {
                __Error.WinIOError(errorCode, string.Empty);
                }
                }
                long num4 = (highSize << 0x20) | ((long) ((ulong) fileSize));
                if ((this._writePos > 0) && ((this._pos + this._writePos) > num4))
                {
                num4 = this._writePos + this._pos;
                }
                return num4;
                }

                Win32Native.GetFileSize uses P/Invoke to GetFileSize in kernel32.dll Solution: store the length in a local variable (like Luc said)

                L Offline
                L Offline
                Luc Pattyn
                wrote on last edited by
                #8

                Right. I didn't know it was that bad. And why don't they use GetFileSizeEx, that one at least returns a long right away. :doh:

                Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


                I only read code that is properly formatted, adding PRE tags is the easiest way to obtain that.


                L 1 Reply Last reply
                0
                • L Luc Pattyn

                  Right. I didn't know it was that bad. And why don't they use GetFileSizeEx, that one at least returns a long right away. :doh:

                  Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


                  I only read code that is properly formatted, adding PRE tags is the easiest way to obtain that.


                  L Offline
                  L Offline
                  Lost User
                  wrote on last edited by
                  #9

                  It is, I think, not even correct for sizes above 4GB. I mean see this: (highSize << 0x20) highSize is an int, and if you try to shift an int by 32, nothing happens, and it's only upcast after the shift. There is just no way anyone they'd let something like this in after all the patches, so something else is going on. I went back to the reflector to check the MSIL:

                  L\_004a: conv.i8 <--
                  L\_004b: ldc.i4.s 0x20
                  L\_004d: shl 
                  

                  edit: this must be the "offending" part of the code, it's the only place in the code where there is a shift by 0x20 So the actual code is right after all, that means it's a bug in Reflector, right? Or am I missing something?

                  L 1 Reply Last reply
                  0
                  • L Lost User

                    It is, I think, not even correct for sizes above 4GB. I mean see this: (highSize << 0x20) highSize is an int, and if you try to shift an int by 32, nothing happens, and it's only upcast after the shift. There is just no way anyone they'd let something like this in after all the patches, so something else is going on. I went back to the reflector to check the MSIL:

                    L\_004a: conv.i8 <--
                    L\_004b: ldc.i4.s 0x20
                    L\_004d: shl 
                    

                    edit: this must be the "offending" part of the code, it's the only place in the code where there is a shift by 0x20 So the actual code is right after all, that means it's a bug in Reflector, right? Or am I missing something?

                    L Offline
                    L Offline
                    Luc Pattyn
                    wrote on last edited by
                    #10
                    1. Well spotted 2) I looked into it, and IL is OK, C# "disassembly" is wrong. Not the first bug in Reflector. 3) See, I would have used GetFileSizeEx and not have had the opportunity to make that mistake. But then it only exists since Windows Server 2000, so it would never have worked on Win98/Me . :)

                    Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


                    I only read code that is properly formatted, adding PRE tags is the easiest way to obtain that.


                    S 1 Reply Last reply
                    0
                    • L Lost User

                      The point, as I understand it, was that calling fsB.get_Length (which is what you're doing when you ask the value of fsB.Length) may secretly be doing something that takes more than a reasonable amount of time, which is true. As proof, here is the code for FileStream.Length

                      public override long get_Length()
                      {
                      if (this._handle.IsClosed)
                      {
                      __Error.FileNotOpen();
                      }
                      if (!this.CanSeek)
                      {
                      __Error.SeekNotSupported();
                      }
                      int highSize = 0;
                      int fileSize = 0;
                      fileSize = Win32Native.GetFileSize(this._handle, out highSize);
                      if (fileSize == -1)
                      {
                      int errorCode = Marshal.GetLastWin32Error();
                      if (errorCode != 0)
                      {
                      __Error.WinIOError(errorCode, string.Empty);
                      }
                      }
                      long num4 = (highSize << 0x20) | ((long) ((ulong) fileSize));
                      if ((this._writePos > 0) && ((this._pos + this._writePos) > num4))
                      {
                      num4 = this._writePos + this._pos;
                      }
                      return num4;
                      }

                      Win32Native.GetFileSize uses P/Invoke to GetFileSize in kernel32.dll Solution: store the length in a local variable (like Luc said)

                      S Offline
                      S Offline
                      SimpleData
                      wrote on last edited by
                      #11

                      Now I got the idea. Thank you for your answers, this was a really hard thing to spot, for me. :)

                      1 Reply Last reply
                      0
                      • L Luc Pattyn
                        1. Well spotted 2) I looked into it, and IL is OK, C# "disassembly" is wrong. Not the first bug in Reflector. 3) See, I would have used GetFileSizeEx and not have had the opportunity to make that mistake. But then it only exists since Windows Server 2000, so it would never have worked on Win98/Me . :)

                        Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]


                        I only read code that is properly formatted, adding PRE tags is the easiest way to obtain that.


                        S Offline
                        S Offline
                        SimpleData
                        wrote on last edited by
                        #12

                        Thank you all for your help. Now I got the idea and solved the problem. It would take me much longer to spot the cause by myself.

                        1 Reply Last reply
                        0
                        Reply
                        • Reply as topic
                        Log in to reply
                        • Oldest to Newest
                        • Newest to Oldest
                        • Most Votes


                        • Login

                        • Don't have an account? Register

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • World
                        • Users
                        • Groups