Skip to content

Make the rot13 test filter stream its output #958

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 16, 2015

Conversation

nulltoken
Copy link
Member

Various enhancements to the test filters

@nulltoken nulltoken changed the title [WIP] Make the rot13 test filter stream its output Make the rot13 test filter stream its output Feb 14, 2015
@nulltoken
Copy link
Member Author

/cc @ammeep

@nulltoken
Copy link
Member Author

Applying the following patch on top of this PR

diff --git a/LibGit2Sharp.Tests/FilterSubstitutionCipherFixture.cs b/LibGit2Sharp.Tests/FilterSubstitutionCipherFixture.cs
index f2fc14b..d21b1e8 100644
--- a/LibGit2Sharp.Tests/FilterSubstitutionCipherFixture.cs
+++ b/LibGit2Sharp.Tests/FilterSubstitutionCipherFixture.cs
@@ -11,8 +11,31 @@ public class FilterSubstitutionCipherFixture : BaseFixture
         [Fact]
         public void CorrectlyEncodesAndDecodesInput()
         {
-            const string decodedInput = "This is a substitution cipher";
-            const string encodedInput = "Guvf vf n fhofgvghgvba pvcure";
+            string decodedInput = "This is a substitution cipher";
+            string encodedInput = "Guvf vf n fhofgvghgvba pvcure";
+
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;

             var attributes = new List<string> { ".rot13" };
             var filter = new SubstitutionCipherFilter("ROT13", attributes);
@@ -25,7 +48,9 @@ public void CorrectlyEncodesAndDecodesInput()
             using (var repo = new Repository(repoPath, repositoryOptions))

             {
+                Console.WriteLine("Before Stage() call");
                 var blob = CommitOnBranchAndReturnDatabaseBlob(repo, fileName, decodedInput);
+                Console.WriteLine("After Stage() call");
                 var textDetected = blob.GetContentText();

                 Assert.Equal(encodedInput, textDetected);
@@ -37,7 +62,9 @@ public void CorrectlyEncodesAndDecodesInput()

                 DeleteFile(repo, fileName);

+                Console.WriteLine("Before Checkout() call");
                 repo.Checkout("master");
+                Console.WriteLine("After Checkout() call");

                 var fileContents = ReadTextFromFile(repo, fileName);
                 Assert.Equal(1, filter.SmudgeCalledCount);

diff --git a/LibGit2Sharp/Core/GitBufWriteStream.cs b/LibGit2Sharp/Core/GitBufWriteStream.cs
index f727fec..e31f743 100644
--- a/LibGit2Sharp/Core/GitBufWriteStream.cs
+++ b/LibGit2Sharp/Core/GitBufWriteStream.cs
@@ -37,6 +37,9 @@ public override int Read(byte[] buffer, int offset, int count)

         public override void Write(byte[] buffer, int offset, int count)
         {
+            Console.WriteLine("-------");
+            Console.WriteLine("Count={0}", count);
+
             AutoGrowBuffer(count);

             Proxy.git_buf_put(gitBufPointer, buffer, offset, count);
@@ -60,6 +63,10 @@ private void AutoGrowBuffer(int count)

             var targetSize = (ulong)(1.5 * (asize + ulongCount));

+            Console.WriteLine("Size={0}", size);
+            Console.WriteLine("ASize={0}", asize);
+            Console.WriteLine("TargetSize={0}", targetSize);
+
             Proxy.git_buf_grow(gitBufPointer, targetSize);
         }

Will output the following when running the rot13 test

------ Test started: Assembly: LibGit2Sharp.Tests.dll ------

Output from LibGit2Sharp.Tests.FilterSubstitutionCipherFixture.CorrectlyEncodesAndDecodesInput:
  Before Stage() call
  -------
  Count=4095
  Size=0
  ASize=1024
  TargetSize=7678
  -------
  Count=4095
  Size=4095
  ASize=7776
  TargetSize=17806
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  Size=24570
  ASize=26248
  TargetSize=45514
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  Size=53235
  ASize=59064
  TargetSize=94738
  -------
  Count=2062
  After Stage() call
  Before Checkout() call
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=4095
  -------
  Count=2062
  Size=57330
  ASize=59400
  TargetSize=92193
  After Checkout() call

1 passed, 0 failed, 0 skipped, took 3,04 seconds (xUnit.net 1.9.2 build 1705).

/cc @carlosmn @ammeep

@nulltoken nulltoken mentioned this pull request Feb 14, 2015
5 tasks
@carlosmn
Copy link
Member

Since you're using 90% of the buffer being filled after adding to it, the last auto-grow you perform in C# is unnecessary, and you waste about 80kB altogether. It's not too big a deal, as the OS often just won't actually give you that memory, but it could be an issue in 32-bit mode if you handle a lot of large files, as you might waste several MB of address space.

If you skipped the auto-grow and let the git_buf do it, I expect we would see each buffer stay at around 60kB.

@nulltoken
Copy link
Member Author

If you skipped the auto-grow and let the git_buf do it, I expect we would see each buffer stay at around 60kB.

I agree, but that would lead to realloc the native buffer with each output of 4KB.

With current implementation, for one Stage() call, beside the initial pre-allocation, we realloc 4 times. Without it, we'd realloc 15 times.

I'm not a memory wizard. Fewer reallocs or fewer wasted memory... Which one would be better? I'll gladly update the PR accordingly.

@carlosmn
Copy link
Member

I agree, but that would lead to realloc the native buffer with each output of 4KB.
With current implementation, for one Stage() call, beside the initial pre-allocation, we realloc 4 times. Without it, we'd realloc 15 times.

How do you figure that? git_buf also uses a 1.5 multiplier on the target size, so after 4kB the buffer should grow to 12kB ((4 + 4) * 1.5), assuming you pre-allocate 4kB. If you just leave it alone the first put should allocate 6kB and the second put should get you to 12kB as well. The next time you need to reallocate you'd go to 24kB and then 42kB.

@nulltoken
Copy link
Member Author

@carlosmn Dammit! You're right. I forgot that git_buf_put() was also auto-growing in advance.

Dropped the managed implementation.

Applying the following patch

diff --git a/LibGit2Sharp.Tests/FilterSubstitutionCipherFixture.cs b/LibGit2Sharp.Tests/FilterSubstitutionCipherFixture.cs
index f2fc14b..d21b1e8 100644
--- a/LibGit2Sharp.Tests/FilterSubstitutionCipherFixture.cs
+++ b/LibGit2Sharp.Tests/FilterSubstitutionCipherFixture.cs
@@ -11,8 +11,31 @@ public class FilterSubstitutionCipherFixture : BaseFixture
         [Fact]
         public void CorrectlyEncodesAndDecodesInput()
         {
-            const string decodedInput = "This is a substitution cipher";
-            const string encodedInput = "Guvf vf n fhofgvghgvba pvcure";
+            string decodedInput = "This is a substitution cipher";
+            string encodedInput = "Guvf vf n fhofgvghgvba pvcure";
+
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;
+            decodedInput += decodedInput;
+            encodedInput += encodedInput;

             var attributes = new List<string> { ".rot13" };
             var filter = new SubstitutionCipherFilter("ROT13", attributes);
@@ -25,7 +48,9 @@ public void CorrectlyEncodesAndDecodesInput()
             using (var repo = new Repository(repoPath, repositoryOptions))

             {
+                Console.WriteLine("Before Stage() call");
                 var blob = CommitOnBranchAndReturnDatabaseBlob(repo, fileName, decodedInput);
+                Console.WriteLine("After Stage() call");
                 var textDetected = blob.GetContentText();

                 Assert.Equal(encodedInput, textDetected);
@@ -37,7 +62,9 @@ public void CorrectlyEncodesAndDecodesInput()

                 DeleteFile(repo, fileName);

+                Console.WriteLine("Before Checkout() call");
                 repo.Checkout("master");
+                Console.WriteLine("After Checkout() call");

                 var fileContents = ReadTextFromFile(repo, fileName);
                 Assert.Equal(1, filter.SmudgeCalledCount);
diff --git a/LibGit2Sharp/Core/GitBufWriteStream.cs b/LibGit2Sharp/Core/GitBufWriteStream.cs
index 7cc281f..f4c7204 100644
--- a/LibGit2Sharp/Core/GitBufWriteStream.cs
+++ b/LibGit2Sharp/Core/GitBufWriteStream.cs
@@ -37,6 +37,17 @@ public override int Read(byte[] buffer, int offset, int count)

         public override void Write(byte[] buffer, int offset, int count)
         {
+            var gitBuf = gitBufPointer.MarshalAs<GitBuf>();
+
+            var ulongCount = Convert.ToUInt64(count);
+            var asize = (ulong)gitBuf.asize;
+            var size = (ulong)gitBuf.size;
+
+            Console.WriteLine("-------");
+            Console.WriteLine("Count={0}", count);
+            Console.WriteLine("Size={0}", size);
+            Console.WriteLine("Asize={0}", asize);
+
             Proxy.git_buf_put(gitBufPointer, buffer, offset, count);
         }

now ouputs the following

------ Test started: Assembly: LibGit2Sharp.Tests.dll ------

Output from LibGit2Sharp.Tests.FilterSubstitutionCipherFixture.CorrectlyEncodesAndDecodesInput:
  Before Stage() call
  -------
  Count=4095
  Size=0
  Asize=4096
  -------
  Count=4095
  Size=4095
  Asize=4096
  -------
  Count=4095
  Size=8190
  Asize=9216
  -------
  Count=4095
  Size=12285
  Asize=13824
  -------
  Count=4095
  Size=16380
  Asize=20736
  -------
  Count=4095
  Size=20475
  Asize=20736
  -------
  Count=4095
  Size=24570
  Asize=31104
  -------
  Count=4095
  Size=28665
  Asize=31104
  -------
  Count=4095
  Size=32760
  Asize=46656
  -------
  Count=4095
  Size=36855
  Asize=46656
  -------
  Count=4095
  Size=40950
  Asize=46656
  -------
  Count=4095
  Size=45045
  Asize=46656
  -------
  Count=4095
  Size=49140
  Asize=69984
  -------
  Count=4095
  Size=53235
  Asize=69984
  -------
  Count=2062
  Size=57330
  Asize=69984
  After Stage() call
  Before Checkout() call
  -------
  Count=4095
  Size=0
  Asize=59400
  -------
  Count=4095
  Size=4095
  Asize=59400
  -------
  Count=4095
  Size=8190
  Asize=59400
  -------
  Count=4095
  Size=12285
  Asize=59400
  -------
  Count=4095
  Size=16380
  Asize=59400
  -------
  Count=4095
  Size=20475
  Asize=59400
  -------
  Count=4095
  Size=24570
  Asize=59400
  -------
  Count=4095
  Size=28665
  Asize=59400
  -------
  Count=4095
  Size=32760
  Asize=59400
  -------
  Count=4095
  Size=36855
  Asize=59400
  -------
  Count=4095
  Size=40950
  Asize=59400
  -------
  Count=4095
  Size=45045
  Asize=59400
  -------
  Count=4095
  Size=49140
  Asize=59400
  -------
  Count=4095
  Size=53235
  Asize=59400
  -------
  Count=2062
  Size=57330
  Asize=59400
  After Checkout() call

1 passed, 0 failed, 0 skipped, took 4,44 seconds (xUnit.net 1.9.2 build 1705).

@nulltoken
Copy link
Member Author

Down to 6 reallocs (with much less wasted memory) when staging.

@ammeep
Copy link
Member

ammeep commented Feb 16, 2015

This is fantastic ✨ I'm happy to merge this in if you are done with it?

@nulltoken
Copy link
Member Author

I'm done. Merge at your will!

@ammeep
Copy link
Member

ammeep commented Feb 16, 2015

💖 Thanks you

ammeep pushed a commit that referenced this pull request Feb 16, 2015
Make the rot13 test filter stream its output
@ammeep ammeep merged commit f8f6f4e into register-custom-filters Feb 16, 2015
@ammeep ammeep deleted the ntk/test_filters branch February 16, 2015 19:51
@nulltoken
Copy link
Member Author

Wow... You're fast!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants